- /// These are the inventory specific request/response state
- /// extensions.
- ///
-
- internal UUID uuid = UUID.Zero;
- internal UserProfileData userProfile = null;
- internal AvatarAppearance userAppearance = null;
-
- internal AppearanceRequestData(OSHttpRequest request, OSHttpResponse response, string prefix)
- : base(request, response, prefix)
- {
- }
-
- }
-
- #endregion Appearance RequestData extension
-
- }
-}
diff --git a/OpenSim/ApplicationPlugins/Rest/Inventory/RestAssetServices.cs b/OpenSim/ApplicationPlugins/Rest/Inventory/RestAssetServices.cs
deleted file mode 100644
index 4ba3d77..0000000
--- a/OpenSim/ApplicationPlugins/Rest/Inventory/RestAssetServices.cs
+++ /dev/null
@@ -1,383 +0,0 @@
-/*
- * 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 OpenSimulator 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.Xml;
-using OpenMetaverse;
-using OpenSim.Framework;
-using OpenSim.Framework.Servers;
-using OpenSim.Framework.Servers.HttpServer;
-
-namespace OpenSim.ApplicationPlugins.Rest.Inventory
-{
- public class RestAssetServices : IRest
- {
- private bool enabled = false;
- private string qPrefix = "assets";
-
- // A simple constructor is used to handle any once-only
- // initialization of working classes.
-
- public RestAssetServices()
- {
- Rest.Log.InfoFormat("{0} Asset services initializing", MsgId);
- Rest.Log.InfoFormat("{0} Using REST Implementation Version {1}", MsgId, Rest.Version);
-
- // If the handler specifies a relative path for its domain
- // then we must add the standard absolute prefix, e.g. /admin
-
- if (!qPrefix.StartsWith(Rest.UrlPathSeparator))
- {
- Rest.Log.InfoFormat("{0} Prefixing domain name ({1})", MsgId, qPrefix);
- qPrefix = String.Format("{0}{1}{2}", Rest.Prefix, Rest.UrlPathSeparator, qPrefix);
- Rest.Log.InfoFormat("{0} Fully qualified domain name is <{1}>", MsgId, qPrefix);
- }
-
- // Register interface using the fully-qualified prefix
-
- Rest.Plugin.AddPathHandler(DoAsset, qPrefix, Allocate);
-
- // Activate if all went OK
-
- enabled = true;
-
- Rest.Log.InfoFormat("{0} Asset services initialization complete", MsgId);
- }
-
- // Post-construction, pre-enabled initialization opportunity
- // Not currently exploited.
-
- public void Initialize()
- {
- }
-
- // Called by the plug-in to halt REST processing. Local processing is
- // disabled, and control blocks until all current processing has
- // completed. No new processing will be started
-
- public void Close()
- {
- enabled = false;
- Rest.Log.InfoFormat("{0} Asset services ({1}) closing down", MsgId, qPrefix);
- }
-
- // Properties
-
- internal string MsgId
- {
- get { return Rest.MsgId; }
- }
-
- #region Interface
-
- private RequestData Allocate(OSHttpRequest request, OSHttpResponse response, string prefix)
- {
- return (RequestData) new AssetRequestData(request, response, prefix);
- }
-
- // Asset Handler
-
- private void DoAsset(RequestData rparm)
- {
- if (!enabled) return;
-
- AssetRequestData rdata = (AssetRequestData) rparm;
-
- Rest.Log.DebugFormat("{0} REST Asset handler ({1}) ENTRY", MsgId, qPrefix);
-
- // Now that we know this is a serious attempt to
- // access inventory data, we should find out who
- // is asking, and make sure they are authorized
- // to do so. We need to validate the caller's
- // identity before revealing anything about the
- // status quo. Authenticate throws an exception
- // via Fail if no identity information is present.
- //
- // With the present HTTP server we can't use the
- // builtin authentication mechanisms because they
- // would be enforced for all in-bound requests.
- // Instead we look at the headers ourselves and
- // handle authentication directly.
-
- try
- {
- if (!rdata.IsAuthenticated)
- {
- rdata.Fail(Rest.HttpStatusCodeNotAuthorized, String.Format("user \"{0}\" could not be authenticated"));
- }
- }
- catch (RestException e)
- {
- if (e.statusCode == Rest.HttpStatusCodeNotAuthorized)
- {
- Rest.Log.WarnFormat("{0} User not authenticated", MsgId);
- Rest.Log.DebugFormat("{0} Authorization header: {1}", MsgId,
- rdata.request.Headers.Get("Authorization"));
- }
- else
- {
- Rest.Log.ErrorFormat("{0} User authentication failed", MsgId);
- Rest.Log.DebugFormat("{0} Authorization header: {1}", MsgId,
- rdata.request.Headers.Get("Authorization"));
- }
- throw (e);
- }
-
- // Remove the prefix and what's left are the parameters. If we don't have
- // the parameters we need, fail the request. Parameters do NOT include
- // any supplied query values.
-
- if (rdata.Parameters.Length > 0)
- {
- switch (rdata.method)
- {
- case "get" :
- DoGet(rdata);
- break;
- case "put" :
- DoPut(rdata);
- break;
- case "post" :
- DoPost(rdata);
- break;
- case "delete" :
- default :
- Rest.Log.WarnFormat("{0} Asset: Method not supported: {1}",
- MsgId, rdata.method);
- rdata.Fail(Rest.HttpStatusCodeBadRequest,String.Format("method <{0}> not supported", rdata.method));
- break;
- }
- }
- else
- {
- Rest.Log.WarnFormat("{0} Asset: No agent information provided", MsgId);
- rdata.Fail(Rest.HttpStatusCodeBadRequest, "no agent information provided");
- }
-
- Rest.Log.DebugFormat("{0} REST Asset handler EXIT", MsgId);
- }
-
- #endregion Interface
-
- ///
- /// The only parameter we recognize is a UUID.If an asset with this identification is
- /// found, it's content, base-64 encoded, is returned to the client.
- ///
-
- private void DoGet(AssetRequestData rdata)
- {
- Rest.Log.DebugFormat("{0} REST Asset handler, Method = <{1}> ENTRY", MsgId, rdata.method);
-
- if (rdata.Parameters.Length == 1)
- {
- UUID uuid = new UUID(rdata.Parameters[0]);
- AssetBase asset = Rest.AssetServices.Get(uuid.ToString());
-
- if (asset != null)
- {
- Rest.Log.DebugFormat("{0} Asset located <{1}>", MsgId, rdata.Parameters[0]);
-
- rdata.initXmlWriter();
-
- rdata.writer.WriteStartElement(String.Empty,"Asset",String.Empty);
-
- rdata.writer.WriteAttributeString("id", asset.ID);
- rdata.writer.WriteAttributeString("name", asset.Name);
- rdata.writer.WriteAttributeString("desc", asset.Description);
- rdata.writer.WriteAttributeString("type", asset.Type.ToString());
- rdata.writer.WriteAttributeString("local", asset.Local.ToString());
- rdata.writer.WriteAttributeString("temporary", asset.Temporary.ToString());
-
- rdata.writer.WriteBase64(asset.Data,0,asset.Data.Length);
-
- rdata.writer.WriteFullEndElement();
-
- }
- else
- {
- Rest.Log.DebugFormat("{0} Invalid parameters: <{1}>", MsgId, rdata.path);
- rdata.Fail(Rest.HttpStatusCodeNotFound, "invalid parameters");
- }
- }
-
- rdata.Complete();
- rdata.Respond(String.Format("Asset <{0}> : Normal completion", rdata.method));
-
- }
-
- ///
- /// UPDATE existing item, if it exists. URI identifies the item in question.
- /// The only parameter we recognize is a UUID. The enclosed asset data (base-64 encoded)
- /// is decoded and stored in the database, identified by the supplied UUID.
- ///
- private void DoPut(AssetRequestData rdata)
- {
- bool modified = false;
- bool created = false;
-
- AssetBase asset = null;
-
- Rest.Log.DebugFormat("{0} REST Asset handler, Method = <{1}> ENTRY", MsgId, rdata.method);
-
- if (rdata.Parameters.Length == 1)
- {
-
- rdata.initXmlReader();
- XmlReader xml = rdata.reader;
-
- if (!xml.ReadToFollowing("Asset"))
- {
- Rest.Log.DebugFormat("{0} Invalid request data: <{1}>", MsgId, rdata.path);
- rdata.Fail(Rest.HttpStatusCodeBadRequest,"invalid request data");
- }
-
- UUID uuid = new UUID(rdata.Parameters[0]);
- asset = Rest.AssetServices.Get(uuid.ToString());
-
- modified = (asset != null);
- created = !modified;
-
- asset = new AssetBase(uuid, xml.GetAttribute("name"), SByte.Parse(xml.GetAttribute("type")), UUID.Zero.ToString());
- asset.Description = xml.GetAttribute("desc");
- asset.Local = Int32.Parse(xml.GetAttribute("local")) != 0;
- asset.Temporary = Int32.Parse(xml.GetAttribute("temporary")) != 0;
- asset.Data = Convert.FromBase64String(xml.ReadElementContentAsString("Asset", ""));
-
- if (asset.ID != rdata.Parameters[0])
- {
- Rest.Log.WarnFormat("{0} URI and payload disagree on UUID U:{1} vs P:{2}",
- MsgId, rdata.Parameters[0], asset.ID);
- }
-
- Rest.AssetServices.Store(asset);
-
- }
- else
- {
- Rest.Log.DebugFormat("{0} Invalid parameters: <{1}>", MsgId, rdata.path);
- rdata.Fail(Rest.HttpStatusCodeNotFound, "invalid parameters");
- }
-
- if (created)
- {
- rdata.appendStatus(String.Format(" Created asset {0}, UUID {1}
", asset.Name, asset.FullID));
- rdata.Complete(Rest.HttpStatusCodeCreated);
- }
- else
- {
- if (modified)
- {
- rdata.appendStatus(String.Format("
Modified asset {0}, UUID {1}
", asset.Name, asset.FullID));
- rdata.Complete(Rest.HttpStatusCodeOK);
- }
- else
- {
- rdata.Complete(Rest.HttpStatusCodeNoContent);
- }
- }
-
- rdata.Respond(String.Format("Asset {0} : Normal completion", rdata.method));
-
- }
-
- ///
- /// CREATE new item, replace if it exists. URI identifies the context for the item in question.
- /// No parameters are required for POST, just thepayload.
- ///
-
- private void DoPost(AssetRequestData rdata)
- {
-
- bool modified = false;
- bool created = false;
-
- Rest.Log.DebugFormat("{0} REST Asset handler, Method = <{1}> ENTRY", MsgId, rdata.method);
-
- if (rdata.Parameters.Length != 0)
- {
- Rest.Log.WarnFormat("{0} Parameters ignored <{1}>", MsgId, rdata.path);
- Rest.Log.InfoFormat("{0} POST of an asset has no parameters", MsgId, rdata.path);
- }
-
- rdata.initXmlReader();
- XmlReader xml = rdata.reader;
-
- if (!xml.ReadToFollowing("Asset"))
- {
- Rest.Log.DebugFormat("{0} Invalid request data: <{1}>", MsgId, rdata.path);
- rdata.Fail(Rest.HttpStatusCodeBadRequest,"invalid request data");
- }
-
- UUID uuid = new UUID(xml.GetAttribute("id"));
- AssetBase asset = Rest.AssetServices.Get(uuid.ToString());
-
- modified = (asset != null);
- created = !modified;
-
- asset = new AssetBase(uuid, xml.GetAttribute("name"), SByte.Parse(xml.GetAttribute("type")), UUID.Zero.ToString());
- asset.Description = xml.GetAttribute("desc");
- asset.Local = Int32.Parse(xml.GetAttribute("local")) != 0;
- asset.Temporary = Int32.Parse(xml.GetAttribute("temporary")) != 0;
- asset.Data = Convert.FromBase64String(xml.ReadElementContentAsString("Asset", ""));
-
- Rest.AssetServices.Store(asset);
-
- if (created)
- {
- rdata.appendStatus(String.Format("
Created asset {0}, UUID {1}
", asset.Name, asset.FullID));
- rdata.Complete(Rest.HttpStatusCodeCreated);
- }
- else
- {
- if (modified)
- {
- rdata.appendStatus(String.Format("
Modified asset {0}, UUID {1}
", asset.Name, asset.FullID));
- rdata.Complete(Rest.HttpStatusCodeOK);
- }
- else
- {
- rdata.Complete(Rest.HttpStatusCodeNoContent);
- }
- }
-
- rdata.Respond(String.Format("Asset {0} : Normal completion", rdata.method));
-
- }
-
- ///
- /// Asset processing has no special data area requirements.
- ///
-
- internal class AssetRequestData : RequestData
- {
- internal AssetRequestData(OSHttpRequest request, OSHttpResponse response, string prefix)
- : base(request, response, prefix)
- {
- }
- }
- }
-}
diff --git a/OpenSim/ApplicationPlugins/Rest/Inventory/RestFileServices.cs b/OpenSim/ApplicationPlugins/Rest/Inventory/RestFileServices.cs
deleted file mode 100644
index e79d2bd..0000000
--- a/OpenSim/ApplicationPlugins/Rest/Inventory/RestFileServices.cs
+++ /dev/null
@@ -1,448 +0,0 @@
-/*
- * 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 OpenSimulator 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.Xml;
-using System.IO;
-using OpenMetaverse;
-using OpenSim.Framework;
-using OpenSim.Framework.Servers;
-using OpenSim.Framework.Servers.HttpServer;
-
-namespace OpenSim.ApplicationPlugins.Rest.Inventory
-{
- public class RestFileServices : IRest
- {
- private bool enabled = false;
- private string qPrefix = "files";
-
- // A simple constructor is used to handle any once-only
- // initialization of working classes.
-
- public RestFileServices()
- {
- Rest.Log.InfoFormat("{0} File services initializing", MsgId);
- Rest.Log.InfoFormat("{0} Using REST Implementation Version {1}", MsgId, Rest.Version);
-
- // If the handler specifies a relative path for its domain
- // then we must add the standard absolute prefix, e.g. /admin
-
- if (!qPrefix.StartsWith(Rest.UrlPathSeparator))
- {
- Rest.Log.InfoFormat("{0} Prefixing domain name ({1})", MsgId, qPrefix);
- qPrefix = String.Format("{0}{1}{2}", Rest.Prefix, Rest.UrlPathSeparator, qPrefix);
- Rest.Log.InfoFormat("{0} Fully qualified domain name is <{1}>", MsgId, qPrefix);
- }
-
- // Register interface using the fully-qualified prefix
-
- Rest.Plugin.AddPathHandler(DoFile, qPrefix, Allocate);
-
- // Activate if all went OK
-
- enabled = true;
-
- Rest.Log.InfoFormat("{0} File services initialization complete", MsgId);
- }
-
- // Post-construction, pre-enabled initialization opportunity
- // Not currently exploited.
-
- public void Initialize()
- {
- }
-
- // Called by the plug-in to halt REST processing. Local processing is
- // disabled, and control blocks until all current processing has
- // completed. No new processing will be started
-
- public void Close()
- {
- enabled = false;
- Rest.Log.InfoFormat("{0} File services ({1}) closing down", MsgId, qPrefix);
- }
-
- // Properties
-
- internal string MsgId
- {
- get { return Rest.MsgId; }
- }
-
- #region Interface
-
- private RequestData Allocate(OSHttpRequest request, OSHttpResponse response, string prefix)
- {
- return (RequestData) new FileRequestData(request, response, prefix);
- }
-
- // Asset Handler
-
- private void DoFile(RequestData rparm)
- {
- if (!enabled) return;
-
- FileRequestData rdata = (FileRequestData) rparm;
-
- Rest.Log.DebugFormat("{0} REST File handler ({1}) ENTRY", MsgId, qPrefix);
-
- // Now that we know this is a serious attempt to
- // access file data, we should find out who
- // is asking, and make sure they are authorized
- // to do so. We need to validate the caller's
- // identity before revealing anything about the
- // status quo. Authenticate throws an exception
- // via Fail if no identity information is present.
- //
- // With the present HTTP server we can't use the
- // builtin authentication mechanisms because they
- // would be enforced for all in-bound requests.
- // Instead we look at the headers ourselves and
- // handle authentication directly.
-
- try
- {
- if (!rdata.IsAuthenticated)
- {
- rdata.Fail(Rest.HttpStatusCodeNotAuthorized, String.Format("user \"{0}\" could not be authenticated"));
- }
- }
- catch (RestException e)
- {
- if (e.statusCode == Rest.HttpStatusCodeNotAuthorized)
- {
- Rest.Log.WarnFormat("{0} User not authenticated", MsgId);
- Rest.Log.DebugFormat("{0} Authorization header: {1}", MsgId,
- rdata.request.Headers.Get("Authorization"));
- }
- else
- {
- Rest.Log.ErrorFormat("{0} User authentication failed", MsgId);
- Rest.Log.DebugFormat("{0} Authorization header: {1}", MsgId,
- rdata.request.Headers.Get("Authorization"));
- }
- throw (e);
- }
-
- // Remove the prefix and what's left are the parameters. If we don't have
- // the parameters we need, fail the request. Parameters do NOT include
- // any supplied query values.
-
- if (rdata.Parameters.Length > 0)
- {
- switch (rdata.method)
- {
- case "get" :
- DoGet(rdata);
- break;
- case "put" :
- DoPut(rdata);
- break;
- case "post" :
- DoPost(rdata);
- break;
- case "delete" :
- DoDelete(rdata);
- break;
- default :
- Rest.Log.WarnFormat("{0} File: Method not supported: {1}",
- MsgId, rdata.method);
- rdata.Fail(Rest.HttpStatusCodeBadRequest,String.Format("method <{0}> not supported", rdata.method));
- break;
- }
- }
- else
- {
- Rest.Log.WarnFormat("{0} File: No agent information provided", MsgId);
- rdata.Fail(Rest.HttpStatusCodeBadRequest, "no agent information provided");
- }
-
- Rest.Log.DebugFormat("{0} REST File handler EXIT", MsgId);
-
- }
-
- #endregion Interface
-
- ///
- /// The only parameter we recognize is a UUID.If an asset with this identification is
- /// found, it's content, base-64 encoded, is returned to the client.
- ///
-
- private void DoGet(FileRequestData rdata)
- {
-
- string path = String.Empty;
-
- Rest.Log.DebugFormat("{0} REST File handler, Method = <{1}> ENTRY", MsgId, rdata.method);
-
- if (rdata.Parameters.Length > 1)
- {
- try
- {
- path = rdata.path.Substring(rdata.Parameters[0].Length+qPrefix.Length+2);
- if (File.Exists(path))
- {
- Rest.Log.DebugFormat("{0} File located <{1}>", MsgId, path);
- Byte[] data = File.ReadAllBytes(path);
- rdata.initXmlWriter();
- rdata.writer.WriteStartElement(String.Empty,"File",String.Empty);
- rdata.writer.WriteAttributeString("name", path);
- rdata.writer.WriteBase64(data,0,data.Length);
- rdata.writer.WriteFullEndElement();
- }
- else
- {
- Rest.Log.DebugFormat("{0} Invalid parameters: <{1}>", MsgId, path);
- rdata.Fail(Rest.HttpStatusCodeNotFound, String.Format("invalid parameters : {0}", path));
- }
- }
- catch (Exception e)
- {
- Rest.Log.DebugFormat("{0} Invalid parameters: <{1}>", MsgId, e.Message);
- rdata.Fail(Rest.HttpStatusCodeNotFound, String.Format("invalid parameters : {0} {1}",
- path, e.Message));
- }
- }
-
- rdata.Complete();
- rdata.Respond(String.Format("File <{0}> : Normal completion", rdata.method));
-
- }
-
- ///
- /// UPDATE existing item, if it exists. URI identifies the item in question.
- /// The only parameter we recognize is a UUID. The enclosed asset data (base-64 encoded)
- /// is decoded and stored in the database, identified by the supplied UUID.
- ///
- private void DoPut(FileRequestData rdata)
- {
- bool modified = false;
- bool created = false;
- string path = String.Empty;
-
- Rest.Log.DebugFormat("{0} REST File handler, Method = <{1}> ENTRY", MsgId, rdata.method);
-
- if (rdata.Parameters.Length > 1)
- {
- try
- {
- path = rdata.path.Substring(rdata.Parameters[0].Length+qPrefix.Length+2);
- bool maymod = File.Exists(path);
-
- rdata.initXmlReader();
- XmlReader xml = rdata.reader;
-
- if (!xml.ReadToFollowing("File"))
- {
- Rest.Log.DebugFormat("{0} Invalid request data: <{1}>", MsgId, rdata.path);
- rdata.Fail(Rest.HttpStatusCodeBadRequest,"invalid request data");
- }
-
- Byte[] data = Convert.FromBase64String(xml.ReadElementContentAsString("File", ""));
-
- File.WriteAllBytes(path,data);
- modified = maymod;
- created = ! maymod;
- }
- catch (Exception e)
- {
- Rest.Log.DebugFormat("{0} Exception during file processing : {1}", MsgId,
- e.Message);
- }
- }
- else
- {
- Rest.Log.DebugFormat("{0} Invalid parameters: <{1}>", MsgId, rdata.path);
- rdata.Fail(Rest.HttpStatusCodeNotFound, "invalid parameters");
- }
-
- if (created)
- {
- rdata.appendStatus(String.Format("
Created file {0}
", path));
- rdata.Complete(Rest.HttpStatusCodeCreated);
- }
- else
- {
- if (modified)
- {
- rdata.appendStatus(String.Format("
Modified file {0}
", path));
- rdata.Complete(Rest.HttpStatusCodeOK);
- }
- else
- {
- rdata.Complete(Rest.HttpStatusCodeNoContent);
- }
- }
-
- rdata.Respond(String.Format("File {0} : Normal completion", rdata.method));
-
- }
-
- ///
- /// CREATE new item, replace if it exists. URI identifies the context for the item in question.
- /// No parameters are required for POST, just thepayload.
- ///
-
- private void DoPost(FileRequestData rdata)
- {
-
- bool modified = false;
- bool created = false;
- string path = String.Empty;
-
- Rest.Log.DebugFormat("{0} REST File handler, Method = <{1}> ENTRY", MsgId, rdata.method);
-
- if (rdata.Parameters.Length > 1)
- {
- try
- {
- path = rdata.path.Substring(rdata.Parameters[0].Length+qPrefix.Length+2);
- bool maymod = File.Exists(path);
-
- rdata.initXmlReader();
- XmlReader xml = rdata.reader;
-
- if (!xml.ReadToFollowing("File"))
- {
- Rest.Log.DebugFormat("{0} Invalid request data: <{1}>", MsgId, rdata.path);
- rdata.Fail(Rest.HttpStatusCodeBadRequest,"invalid request data");
- }
-
- Byte[] data = Convert.FromBase64String(xml.ReadElementContentAsString("File", ""));
-
- File.WriteAllBytes(path,data);
- modified = maymod;
- created = ! maymod;
- }
- catch (Exception e)
- {
- Rest.Log.DebugFormat("{0} Exception during file processing : {1}", MsgId,
- e.Message);
- }
- }
- else
- {
- Rest.Log.DebugFormat("{0} Invalid parameters: <{1}>", MsgId, rdata.path);
- rdata.Fail(Rest.HttpStatusCodeNotFound, "invalid parameters");
- }
-
- if (created)
- {
- rdata.appendStatus(String.Format("
Created file {0}
", path));
- rdata.Complete(Rest.HttpStatusCodeCreated);
- }
- else
- {
- if (modified)
- {
- rdata.appendStatus(String.Format("
Modified file {0}
", path));
- rdata.Complete(Rest.HttpStatusCodeOK);
- }
- else
- {
- rdata.Complete(Rest.HttpStatusCodeNoContent);
- }
- }
-
- rdata.Respond(String.Format("File {0} : Normal completion", rdata.method));
-
- }
-
- ///
- /// CREATE new item, replace if it exists. URI identifies the context for the item in question.
- /// No parameters are required for POST, just thepayload.
- ///
-
- private void DoDelete(FileRequestData rdata)
- {
-
- bool modified = false;
- bool created = false;
- string path = String.Empty;
-
- Rest.Log.DebugFormat("{0} REST File handler, Method = <{1}> ENTRY", MsgId, rdata.method);
-
- if (rdata.Parameters.Length > 1)
- {
- try
- {
- path = rdata.path.Substring(rdata.Parameters[0].Length+qPrefix.Length+2);
-
- if (File.Exists(path))
- {
- File.Delete(path);
- }
- }
- catch (Exception e)
- {
- Rest.Log.DebugFormat("{0} Exception during file processing : {1}", MsgId,
- e.Message);
- rdata.Fail(Rest.HttpStatusCodeNotFound, String.Format("invalid parameters : {0} {1}",
- path, e.Message));
- }
- }
- else
- {
- Rest.Log.DebugFormat("{0} Invalid parameters: <{1}>", MsgId, rdata.path);
- rdata.Fail(Rest.HttpStatusCodeNotFound, "invalid parameters");
- }
-
- if (created)
- {
- rdata.appendStatus(String.Format("
Created file {0}
", path));
- rdata.Complete(Rest.HttpStatusCodeCreated);
- }
- else
- {
- if (modified)
- {
- rdata.appendStatus(String.Format("
Modified file {0}
", path));
- rdata.Complete(Rest.HttpStatusCodeOK);
- }
- else
- {
- rdata.Complete(Rest.HttpStatusCodeNoContent);
- }
- }
-
- rdata.Respond(String.Format("File {0} : Normal completion", rdata.method));
-
- }
-
- ///
- /// File processing has no special data area requirements.
- ///
-
- internal class FileRequestData : RequestData
- {
- internal FileRequestData(OSHttpRequest request, OSHttpResponse response, string prefix)
- : base(request, response, prefix)
- {
- }
- }
- }
-}
diff --git a/OpenSim/ApplicationPlugins/Rest/Inventory/RestHandler.cs b/OpenSim/ApplicationPlugins/Rest/Inventory/RestHandler.cs
deleted file mode 100644
index 072bd6f..0000000
--- a/OpenSim/ApplicationPlugins/Rest/Inventory/RestHandler.cs
+++ /dev/null
@@ -1,662 +0,0 @@
-/*
- * 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 OpenSimulator 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.Collections.Generic;
-using System.Reflection;
-using OpenSim.Framework.Servers;
-using OpenSim.Framework.Servers.HttpServer;
-
-namespace OpenSim.ApplicationPlugins.Rest.Inventory
-{
- ///
- /// The class signature reveals the roles that RestHandler plays.
- ///
- /// [1] It is a sub-class of RestPlugin. It inherits and extends
- /// the functionality of this class, constraining it to the
- /// specific needs of this REST implementation. This relates
- /// to the plug-in mechanism supported by OpenSim, the specifics
- /// of which are mostly hidden by RestPlugin.
- /// [2] IRestHandler describes the interface that this class
- /// exports to service implementations. This is the services
- /// management interface.
- /// [3] IHttpAgentHandler describes the interface that is exported
- /// to the BaseHttpServer in support of this particular HTTP
- /// processing model. This is the request interface of the
- /// handler.
- ///
-
- public class RestHandler : RestPlugin, IRestHandler, IHttpAgentHandler
- {
- // Handler tables: both stream and REST are supported. The path handlers and their
- // respective allocators are stored in separate tables.
-
- internal Dictionary pathHandlers = new Dictionary();
- internal Dictionary pathAllocators = new Dictionary();
- internal Dictionary streamHandlers = new Dictionary();
-
- #region local static state
-
- private static bool handlersLoaded = false;
- private static List classes = new List();
- private static List handlers = new List();
- private static Type[] parms = new Type[0];
- private static Object[] args = new Object[0];
-
- ///
- /// This static initializer scans the ASSEMBLY for classes that
- /// export the IRest interface and builds a list of them. These
- /// are later activated by the handler. To add a new handler it
- /// is only necessary to create a new services class that implements
- /// the IRest interface, and recompile the handler. This gives
- /// all of the build-time flexibility of a modular approach
- /// while not introducing yet-another module loader. Note that
- /// multiple assembles can still be built, each with its own set
- /// of handlers. Examples of services classes are RestInventoryServices
- /// and RestSkeleton.
- ///
-
- static RestHandler()
- {
- Module[] mods = Assembly.GetExecutingAssembly().GetModules();
-
- foreach (Module m in mods)
- {
- Type[] types = m.GetTypes();
- foreach (Type t in types)
- {
- try
- {
- if (t.GetInterface("IRest") != null)
- {
- classes.Add(t);
- }
- }
- catch (Exception)
- {
- Rest.Log.WarnFormat("[STATIC-HANDLER]: #0 Error scanning {1}", t);
- Rest.Log.InfoFormat("[STATIC-HANDLER]: #0 {1} is not included", t);
- }
- }
- }
- }
-
- #endregion local static state
-
- #region local instance state
-
- ///
- /// This routine loads all of the handlers discovered during
- /// instance initialization.
- /// A table of all loaded and successfully constructed handlers
- /// is built, and this table is then used by the constructor to
- /// initialize each of the handlers in turn.
- /// NOTE: The loading process does not automatically imply that
- /// the handler has registered any kind of an interface, that
- /// may be (optionally) done by the handler either during
- /// construction, or during initialization.
- ///
- /// I was not able to make this code work within a constructor
- /// so it is isolated within this method.
- ///
-
- private void LoadHandlers()
- {
- lock (handlers)
- {
- if (!handlersLoaded)
- {
- ConstructorInfo ci;
- Object ht;
-
- foreach (Type t in classes)
- {
- try
- {
- ci = t.GetConstructor(parms);
- ht = ci.Invoke(args);
- handlers.Add((IRest)ht);
- }
- catch (Exception e)
- {
- Rest.Log.WarnFormat("{0} Unable to load {1} : {2}", MsgId, t, e.Message);
- }
- }
- handlersLoaded = true;
- }
- }
- }
-
- #endregion local instance state
-
- #region overriding properties
-
- // These properties override definitions
- // in the base class.
-
- // Name is used to differentiate the message header.
-
- public override string Name
- {
- get { return "HANDLER"; }
- }
-
- // Used to partition the .ini configuration space.
-
- public override string ConfigName
- {
- get { return "RestHandler"; }
- }
-
- // We have to rename these because we want
- // to be able to share the values with other
- // classes in our assembly and the base
- // names are protected.
-
- public string MsgId
- {
- get { return base.MsgID; }
- }
-
- public string RequestId
- {
- get { return base.RequestID; }
- }
-
- #endregion overriding properties
-
- #region overriding methods
-
- ///
- /// This method is called by OpenSimMain immediately after loading the
- /// plugin and after basic server setup, but before running any server commands.
- ///
- ///
- /// Note that entries MUST be added to the active configuration files before
- /// the plugin can be enabled.
- ///
-
- public override void Initialise(OpenSimBase openSim)
- {
- try
- {
- // This plugin will only be enabled if the broader
- // REST plugin mechanism is enabled.
-
- //Rest.Log.InfoFormat("{0} Plugin is initializing", MsgId);
-
- base.Initialise(openSim);
-
- // IsEnabled is implemented by the base class and
- // reflects an overall RestPlugin status
-
- if (!IsEnabled)
- {
- //Rest.Log.WarnFormat("{0} Plugins are disabled", MsgId);
- return;
- }
-
- Rest.Log.InfoFormat("{0} Rest <{1}> plugin will be enabled", MsgId, Name);
- Rest.Log.InfoFormat("{0} Configuration parameters read from <{1}>", MsgId, ConfigName);
-
- // These are stored in static variables to make
- // them easy to reach from anywhere in the assembly.
-
- Rest.main = openSim;
- if (Rest.main == null)
- throw new Exception("OpenSim base pointer is null");
-
- Rest.Plugin = this;
- Rest.Config = Config;
- Rest.Prefix = Prefix;
- Rest.GodKey = GodKey;
- Rest.Authenticate = Rest.Config.GetBoolean("authenticate", Rest.Authenticate);
- Rest.Scheme = Rest.Config.GetString("auth-scheme", Rest.Scheme);
- Rest.Secure = Rest.Config.GetBoolean("secured", Rest.Secure);
- Rest.ExtendedEscape = Rest.Config.GetBoolean("extended-escape", Rest.ExtendedEscape);
- Rest.Realm = Rest.Config.GetString("realm", Rest.Realm);
- Rest.DumpAsset = Rest.Config.GetBoolean("dump-asset", Rest.DumpAsset);
- Rest.Fill = Rest.Config.GetBoolean("path-fill", Rest.Fill);
- Rest.DumpLineSize = Rest.Config.GetInt("dump-line-size", Rest.DumpLineSize);
- Rest.FlushEnabled = Rest.Config.GetBoolean("flush-on-error", Rest.FlushEnabled);
-
- // Note: Odd spacing is required in the following strings
-
- Rest.Log.InfoFormat("{0} Authentication is {1}required", MsgId,
- (Rest.Authenticate ? "" : "not "));
-
- Rest.Log.InfoFormat("{0} Security is {1}enabled", MsgId,
- (Rest.Secure ? "" : "not "));
-
- Rest.Log.InfoFormat("{0} Extended URI escape processing is {1}enabled", MsgId,
- (Rest.ExtendedEscape ? "" : "not "));
-
- Rest.Log.InfoFormat("{0} Dumping of asset data is {1}enabled", MsgId,
- (Rest.DumpAsset ? "" : "not "));
-
- // The supplied prefix MUST be absolute
-
- if (Rest.Prefix.Substring(0,1) != Rest.UrlPathSeparator)
- {
- Rest.Log.WarnFormat("{0} Prefix <{1}> is not absolute and must be", MsgId, Rest.Prefix);
- Rest.Log.InfoFormat("{0} Prefix changed to {1}>", MsgId, Rest.Prefix);
- Rest.Prefix = String.Format("{0}{1}", Rest.UrlPathSeparator, Rest.Prefix);
- }
-
- // If data dumping is requested, report on the chosen line
- // length.
-
- if (Rest.DumpAsset)
- {
- Rest.Log.InfoFormat("{0} Dump {1} bytes per line", MsgId, Rest.DumpLineSize);
- }
-
- // Load all of the handlers present in the
- // assembly
-
- // In principle, as we're an application plug-in,
- // most of what needs to be done could be done using
- // static resources, however the Open Sim plug-in
- // model makes this an instance, so that's what we
- // need to be.
- // There is only one Communications manager per
- // server, and by inference, only one each of the
- // user, asset, and inventory servers. So we can cache
- // those using a static initializer.
- // We move all of this processing off to another
- // services class to minimize overlap between function
- // and infrastructure.
-
- LoadHandlers();
-
- // The intention of a post construction initializer
- // is to allow for setup that is dependent upon other
- // activities outside of the agency.
-
- foreach (IRest handler in handlers)
- {
- try
- {
- handler.Initialize();
- }
- catch (Exception e)
- {
- Rest.Log.ErrorFormat("{0} initialization error: {1}", MsgId, e.Message);
- }
- }
-
- // Now that everything is setup we can proceed to
- // add THIS agent to the HTTP server's handler list
-
- // FIXME: If this code is ever to be re-enabled (most of it is disabled already) then this will
- // have to be handled through the AddHttpHandler interface.
-// if (!AddAgentHandler(Rest.Name,this))
-// {
-// Rest.Log.ErrorFormat("{0} Unable to activate handler interface", MsgId);
-// foreach (IRest handler in handlers)
-// {
-// handler.Close();
-// }
-// }
-
- }
- catch (Exception e)
- {
- Rest.Log.ErrorFormat("{0} Plugin initialization has failed: {1}", MsgId, e.Message);
- }
- }
-
- ///
- /// In the interests of efficiency, and because we cannot determine whether
- /// or not this instance will actually be harvested, we clobber the only
- /// anchoring reference to the working state for this plug-in. What the
- /// call to close does is irrelevant to this class beyond knowing that it
- /// can nullify the reference when it returns.
- /// To make sure everything is copacetic we make sure the primary interface
- /// is disabled by deleting the handler from the HTTP server tables.
- ///
-
- public override void Close()
- {
- Rest.Log.InfoFormat("{0} Plugin is terminating", MsgId);
-
- // FIXME: If this code is ever to be re-enabled (most of it is disabled already) then this will
- // have to be handled through the AddHttpHandler interface.
-// try
-// {
-// RemoveAgentHandler(Rest.Name, this);
-// }
-// catch (KeyNotFoundException){}
-
- foreach (IRest handler in handlers)
- {
- handler.Close();
- }
- }
-
- #endregion overriding methods
-
- #region interface methods
-
- ///
- /// This method is called by the HTTP server to match an incoming
- /// request. It scans all of the strings registered by the
- /// underlying handlers and looks for the best match. It returns
- /// true if a match is found.
- /// The matching process could be made arbitrarily complex.
- /// Note: The match is case-insensitive.
- ///
-
- public bool Match(OSHttpRequest request, OSHttpResponse response)
- {
-
- string path = request.RawUrl.ToLower();
-
- // Rest.Log.DebugFormat("{0} Match ENTRY", MsgId);
-
- try
- {
- foreach (string key in pathHandlers.Keys)
- {
- // Rest.Log.DebugFormat("{0} Match testing {1} against agent prefix <{2}>", MsgId, path, key);
-
- // Note that Match will not necessarily find the handler that will
- // actually be used - it does no test for the "closest" fit. It
- // simply reflects that at least one possible handler exists.
-
- if (path.StartsWith(key))
- {
- // Rest.Log.DebugFormat("{0} Matched prefix <{1}>", MsgId, key);
-
- // This apparently odd evaluation is needed to prevent a match
- // on anything other than a URI token boundary. Otherwise we
- // may match on URL's that were not intended for this handler.
-
- return (path.Length == key.Length ||
- path.Substring(key.Length, 1) == Rest.UrlPathSeparator);
- }
- }
-
- path = String.Format("{0}{1}{2}", request.HttpMethod, Rest.UrlMethodSeparator, path);
-
- foreach (string key in streamHandlers.Keys)
- {
- // Rest.Log.DebugFormat("{0} Match testing {1} against stream prefix <{2}>", MsgId, path, key);
-
- // Note that Match will not necessarily find the handler that will
- // actually be used - it does no test for the "closest" fit. It
- // simply reflects that at least one possible handler exists.
-
- if (path.StartsWith(key))
- {
- // Rest.Log.DebugFormat("{0} Matched prefix <{1}>", MsgId, key);
-
- // This apparently odd evaluation is needed to prevent a match
- // on anything other than a URI token boundary. Otherwise we
- // may match on URL's that were not intended for this handler.
-
- return (path.Length == key.Length ||
- path.Substring(key.Length, 1) == Rest.UrlPathSeparator);
- }
- }
- }
- catch (Exception e)
- {
- Rest.Log.ErrorFormat("{0} matching exception for path <{1}> : {2}", MsgId, path, e.Message);
- }
-
- return false;
- }
-
- ///
- /// This is called by the HTTP server once the handler has indicated
- /// that it is able to handle the request.
- /// Preconditions:
- /// [1] request != null and is a valid request object
- /// [2] response != null and is a valid response object
- /// Behavior is undefined if preconditions are not satisfied.
- ///
-
- public bool Handle(OSHttpRequest request, OSHttpResponse response)
- {
- bool handled;
- base.MsgID = base.RequestID;
-
- // Debug only
-
- if (Rest.DEBUG)
- {
- Rest.Log.DebugFormat("{0} ENTRY", MsgId);
- Rest.Log.DebugFormat("{0} Agent: {1}", MsgId, request.UserAgent);
- Rest.Log.DebugFormat("{0} Method: {1}", MsgId, request.HttpMethod);
-
- for (int i = 0; i < request.Headers.Count; i++)
- {
- Rest.Log.DebugFormat("{0} Header [{1}] : <{2}> = <{3}>",
- MsgId, i, request.Headers.GetKey(i), request.Headers.Get(i));
- }
- Rest.Log.DebugFormat("{0} URI: {1}", MsgId, request.RawUrl);
- }
-
- // If a path handler worked we're done, otherwise try any
- // available stream handlers too.
-
- try
- {
- handled = (FindPathHandler(request, response) ||
- FindStreamHandler(request, response));
- }
- catch (Exception e)
- {
- // A raw exception indicates that something we weren't expecting has
- // happened. This should always reflect a shortcoming in the plugin,
- // or a failure to satisfy the preconditions. It should not reflect
- // an error in the request itself. Under such circumstances the state
- // of the request cannot be determined and we are obliged to mark it
- // as 'handled'.
-
- Rest.Log.ErrorFormat("{0} Plugin error: {1}", MsgId, e.Message);
- handled = true;
- }
-
- Rest.Log.DebugFormat("{0} EXIT", MsgId);
-
- return handled;
- }
-
- #endregion interface methods
-
- ///
- /// If there is a stream handler registered that can handle the
- /// request, then fine. If the request is not matched, do
- /// nothing.
- /// Note: The selection is case-insensitive
- ///
-
- private bool FindStreamHandler(OSHttpRequest request, OSHttpResponse response)
- {
- RequestData rdata = new RequestData(request, response, String.Empty);
-
- string bestMatch = String.Empty;
- string path = String.Format("{0}:{1}", rdata.method, rdata.path).ToLower();
-
- Rest.Log.DebugFormat("{0} Checking for stream handler for <{1}>", MsgId, path);
-
- if (!IsEnabled)
- {
- return false;
- }
-
- foreach (string pattern in streamHandlers.Keys)
- {
- if (path.StartsWith(pattern))
- {
- if (pattern.Length > bestMatch.Length)
- {
- bestMatch = pattern;
- }
- }
- }
-
- // Handle using the best match available
-
- if (bestMatch.Length > 0)
- {
- Rest.Log.DebugFormat("{0} Stream-based handler matched with <{1}>", MsgId, bestMatch);
- RestStreamHandler handler = streamHandlers[bestMatch];
- rdata.buffer = handler.Handle(rdata.path, rdata.request.InputStream, rdata.request, rdata.response);
- rdata.AddHeader(rdata.response.ContentType,handler.ContentType);
- rdata.Respond("FindStreamHandler Completion");
- }
-
- return rdata.handled;
- }
-
- ///
- /// Add a stream handler for the designated HTTP method and path prefix.
- /// If the handler is not enabled, the request is ignored. If the path
- /// does not start with the REST prefix, it is added. If method-qualified
- /// path has not already been registered, the method is added to the active
- /// handler table.
- ///
- public void AddStreamHandler(string httpMethod, string path, RestMethod method)
- {
- if (!IsEnabled)
- {
- return;
- }
-
- if (!path.StartsWith(Rest.Prefix))
- {
- path = String.Format("{0}{1}", Rest.Prefix, path);
- }
-
- path = String.Format("{0}{1}{2}", httpMethod, Rest.UrlMethodSeparator, path);
-
- // Conditionally add to the list
-
- if (!streamHandlers.ContainsKey(path))
- {
- streamHandlers.Add(path, new RestStreamHandler(httpMethod, path, method));
- Rest.Log.DebugFormat("{0} Added handler for {1}", MsgId, path);
- }
- else
- {
- Rest.Log.WarnFormat("{0} Ignoring duplicate handler for {1}", MsgId, path);
- }
- }
-
- ///
- /// Given the supplied request/response, if the handler is enabled, the inbound
- /// information is used to match an entry in the active path handler tables, using
- /// the method-qualified path information. If a match is found, then the handler is
- /// invoked. The result is the boolean result of the handler, or false if no
- /// handler was located. The boolean indicates whether or not the request has been
- /// handled, not whether or not the request was successful - that information is in
- /// the response.
- /// Note: The selection process is case-insensitive
- ///
-
- internal bool FindPathHandler(OSHttpRequest request, OSHttpResponse response)
- {
- RequestData rdata = null;
- string bestMatch = null;
-
- if (!IsEnabled)
- {
- return false;
- }
-
- // Conditionally add to the list
-
- Rest.Log.DebugFormat("{0} Checking for path handler for <{1}>", MsgId, request.RawUrl);
-
- foreach (string pattern in pathHandlers.Keys)
- {
- if (request.RawUrl.ToLower().StartsWith(pattern))
- {
- if (String.IsNullOrEmpty(bestMatch) || pattern.Length > bestMatch.Length)
- {
- bestMatch = pattern;
- }
- }
- }
-
- if (!String.IsNullOrEmpty(bestMatch))
- {
- rdata = pathAllocators[bestMatch](request, response, bestMatch);
-
- Rest.Log.DebugFormat("{0} Path based REST handler matched with <{1}>", MsgId, bestMatch);
-
- try
- {
- pathHandlers[bestMatch](rdata);
- }
-
- // A plugin generated error indicates a request-related error
- // that has been handled by the plugin.
-
- catch (RestException r)
- {
- Rest.Log.WarnFormat("{0} Request failed: {1}", MsgId, r.Message);
- }
- }
-
- return (rdata == null) ? false : rdata.handled;
- }
-
- ///
- /// A method handler and a request allocator are stored using the designated
- /// path as a key. If an entry already exists, it is replaced by the new one.
- ///
-
- public void AddPathHandler(RestMethodHandler mh, string path, RestMethodAllocator ra)
- {
- if (!IsEnabled)
- {
- return;
- }
-
- if (pathHandlers.ContainsKey(path))
- {
- Rest.Log.DebugFormat("{0} Replacing handler for <${1}>", MsgId, path);
- pathHandlers.Remove(path);
- }
-
- if (pathAllocators.ContainsKey(path))
- {
- Rest.Log.DebugFormat("{0} Replacing allocator for <${1}>", MsgId, path);
- pathAllocators.Remove(path);
- }
-
- Rest.Log.DebugFormat("{0} Adding path handler for {1}", MsgId, path);
-
- pathHandlers.Add(path, mh);
- pathAllocators.Add(path, ra);
- }
- }
-}
diff --git a/OpenSim/ApplicationPlugins/Rest/Inventory/RestInventoryServices.cs b/OpenSim/ApplicationPlugins/Rest/Inventory/RestInventoryServices.cs
deleted file mode 100644
index 536f167..0000000
--- a/OpenSim/ApplicationPlugins/Rest/Inventory/RestInventoryServices.cs
+++ /dev/null
@@ -1,2343 +0,0 @@
-/*
- * 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 OpenSimulator 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.Collections.Generic;
-using System.Drawing;
-using System.Globalization;
-using System.IO;
-using System.Threading;
-using System.Timers;
-using System.Xml;
-using OpenMetaverse;
-using OpenMetaverse.Imaging;
-using OpenSim.Framework;
-
-using OpenSim.Framework.Servers;
-using OpenSim.Framework.Servers.HttpServer;
-using Timer=System.Timers.Timer;
-
-namespace OpenSim.ApplicationPlugins.Rest.Inventory
-{
- public class RestInventoryServices : IRest
- {
-// private static readonly int PARM_USERID = 0;
-// private static readonly int PARM_PATH = 1;
-
-// private bool enabled = false;
- private string qPrefix = "inventory";
-
-// private static readonly string PRIVATE_ROOT_NAME = "My Inventory";
-
- ///
- /// The constructor makes sure that the service prefix is absolute
- /// and the registers the service handler and the allocator.
- ///
-
- public RestInventoryServices()
- {
- Rest.Log.InfoFormat("{0} Inventory services initializing", MsgId);
- Rest.Log.InfoFormat("{0} Using REST Implementation Version {1}", MsgId, Rest.Version);
-
- // If a relative path was specified for the handler's domain,
- // add the standard prefix to make it absolute, e.g. /admin
-
- if (!qPrefix.StartsWith(Rest.UrlPathSeparator))
- {
- Rest.Log.InfoFormat("{0} Domain is relative, adding absolute prefix", MsgId);
- qPrefix = String.Format("{0}{1}{2}", Rest.Prefix, Rest.UrlPathSeparator, qPrefix);
- Rest.Log.InfoFormat("{0} Domain is now <{1}>", MsgId, qPrefix);
- }
-
- // Register interface using the absolute URI.
-
- Rest.Plugin.AddPathHandler(DoInventory,qPrefix,Allocate);
-
- // Activate if everything went OK
-
-// enabled = true;
-
- Rest.Log.InfoFormat("{0} Inventory services initialization complete", MsgId);
- }
-
- ///
- /// Post-construction, pre-enabled initialization opportunity
- /// Not currently exploited.
- ///
-
- public void Initialize()
- {
- }
-
- ///
- /// Called by the plug-in to halt service processing. Local processing is
- /// disabled.
- ///
-
- public void Close()
- {
-// enabled = false;
- Rest.Log.InfoFormat("{0} Inventory services closing down", MsgId);
- }
-
- ///
- /// This property is declared locally because it is used a lot and
- /// brevity is nice.
- ///
- internal string MsgId
- {
- get { return Rest.MsgId; }
- }
-
- #region Interface
-
- ///
- /// The plugin (RestHandler) calls this method to allocate the request
- /// state carrier for a new request. It is destroyed when the request
- /// completes. All request-instance specific state is kept here. This
- /// is registered when this service provider is registered.
- ///
- /// Inbound HTTP request information
- /// Outbound HTTP request information
- /// REST service domain prefix
- /// A RequestData instance suitable for this service
- private RequestData Allocate(OSHttpRequest request, OSHttpResponse response, string prefix)
- {
- return (RequestData) new InventoryRequestData(request, response, prefix);
- }
-
- ///
- /// This method is registered with the handler when this service provider
- /// is initialized. It is called whenever the plug-in identifies this service
- /// provider as the best match for a given request.
- /// It handles all aspects of inventory REST processing, i.e. /admin/inventory
- ///
- /// A consolidated HTTP request work area
- private void DoInventory(RequestData hdata)
- {
-// InventoryRequestData rdata = (InventoryRequestData) hdata;
-
- Rest.Log.DebugFormat("{0} DoInventory ENTRY", MsgId);
-
- // !!! REFACTORING PROBLEM
-
- //// If we're disabled, do nothing.
-
- //if (!enabled)
- //{
- // return;
- //}
-
- //// Now that we know this is a serious attempt to
- //// access inventory data, we should find out who
- //// is asking, and make sure they are authorized
- //// to do so. We need to validate the caller's
- //// identity before revealing anything about the
- //// status quo. Authenticate throws an exception
- //// via Fail if no identity information is present.
- ////
- //// With the present HTTP server we can't use the
- //// builtin authentication mechanisms because they
- //// would be enforced for all in-bound requests.
- //// Instead we look at the headers ourselves and
- //// handle authentication directly.
-
- //try
- //{
- // if (!rdata.IsAuthenticated)
- // {
- // rdata.Fail(Rest.HttpStatusCodeNotAuthorized,String.Format("user \"{0}\" could not be authenticated", rdata.userName));
- // }
- //}
- //catch (RestException e)
- //{
- // if (e.statusCode == Rest.HttpStatusCodeNotAuthorized)
- // {
- // Rest.Log.WarnFormat("{0} User not authenticated", MsgId);
- // Rest.Log.DebugFormat("{0} Authorization header: {1}", MsgId, rdata.request.Headers.Get("Authorization"));
- // }
- // else
- // {
- // Rest.Log.ErrorFormat("{0} User authentication failed", MsgId);
- // Rest.Log.DebugFormat("{0} Authorization header: {1}", MsgId, rdata.request.Headers.Get("Authorization"));
- // }
- // throw (e);
- //}
-
- //Rest.Log.DebugFormat("{0} Authenticated {1}", MsgId, rdata.userName);
-
- //// We can only get here if we are authorized
- ////
- //// The requestor may have specified an UUID or
- //// a conjoined FirstName LastName string. We'll
- //// try both. If we fail with the first, UUID,
- //// attempt, we try the other. As an example, the
- //// URI for a valid inventory request might be:
- ////
- //// http://:/admin/inventory/Arthur Dent
- ////
- //// Indicating that this is an inventory request for
- //// an avatar named Arthur Dent. This is ALL that is
- //// required to designate a GET for an entire
- //// inventory.
- ////
-
-
- //// Do we have at least a user agent name?
-
- //if (rdata.Parameters.Length < 1)
- //{
- // Rest.Log.WarnFormat("{0} Inventory: No user agent identifier specified", MsgId);
- // rdata.Fail(Rest.HttpStatusCodeBadRequest, "no user identity specified");
- //}
-
- //// The first parameter MUST be the agent identification, either an UUID
- //// or a space-separated First-name Last-Name specification. We check for
- //// an UUID first, if anyone names their character using a valid UUID
- //// that identifies another existing avatar will cause this a problem...
-
- //try
- //{
- // rdata.uuid = new UUID(rdata.Parameters[PARM_USERID]);
- // Rest.Log.DebugFormat("{0} UUID supplied", MsgId);
- // rdata.userProfile = Rest.UserServices.GetUserProfile(rdata.uuid);
- //}
- //catch
- //{
- // string[] names = rdata.Parameters[PARM_USERID].Split(Rest.CA_SPACE);
- // if (names.Length == 2)
- // {
- // Rest.Log.DebugFormat("{0} Agent Name supplied [2]", MsgId);
- // rdata.userProfile = Rest.UserServices.GetUserProfile(names[0],names[1]);
- // }
- // else
- // {
- // Rest.Log.WarnFormat("{0} A Valid UUID or both first and last names must be specified", MsgId);
- // rdata.Fail(Rest.HttpStatusCodeBadRequest, "invalid user identity");
- // }
- //}
-
- //// If the user profile is null then either the server is broken, or the
- //// user is not known. We always assume the latter case.
-
- //if (rdata.userProfile != null)
- //{
- // Rest.Log.DebugFormat("{0} Profile obtained for agent {1} {2}",
- // MsgId, rdata.userProfile.FirstName, rdata.userProfile.SurName);
- //}
- //else
- //{
- // Rest.Log.WarnFormat("{0} No profile for {1}", MsgId, rdata.path);
- // rdata.Fail(Rest.HttpStatusCodeNotFound, "unrecognized user identity");
- //}
-
- //// If we get to here, then we have effectively validated the user's
- //// identity. Now we need to get the inventory. If the server does not
- //// have the inventory, we reject the request with an appropriate explanation.
- ////
- //// Note that inventory retrieval is an asynchronous event, we use the rdata
- //// class instance as the basis for our synchronization.
- ////
-
- //rdata.uuid = rdata.userProfile.ID;
-
- //if (Rest.InventoryServices.HasInventoryForUser(rdata.uuid))
- //{
- // rdata.root = Rest.InventoryServices.GetRootFolder(rdata.uuid);
-
- // Rest.Log.DebugFormat("{0} Inventory Root retrieved for {1} {2}",
- // MsgId, rdata.userProfile.FirstName, rdata.userProfile.SurName);
-
- // Rest.InventoryServices.GetUserInventory(rdata.uuid, rdata.GetUserInventory);
-
- // Rest.Log.DebugFormat("{0} Inventory catalog requested for {1} {2}",
- // MsgId, rdata.userProfile.FirstName, rdata.userProfile.SurName);
-
- // lock (rdata)
- // {
- // if (!rdata.HaveInventory)
- // {
- // rdata.startWD(1000);
- // rdata.timeout = false;
- // Monitor.Wait(rdata);
- // }
- // }
-
- // if (rdata.timeout)
- // {
- // Rest.Log.WarnFormat("{0} Inventory not available for {1} {2}. No response from service.",
- // MsgId, rdata.userProfile.FirstName, rdata.userProfile.SurName);
- // rdata.Fail(Rest.HttpStatusCodeServerError, "inventory server not responding");
- // }
-
- // if (rdata.root == null)
- // {
- // Rest.Log.WarnFormat("{0} Inventory is not available [1] for agent {1} {2}",
- // MsgId, rdata.userProfile.FirstName, rdata.userProfile.SurName);
- // rdata.Fail(Rest.HttpStatusCodeServerError, "inventory retrieval failed");
- // }
-
- //}
- //else
- //{
- // Rest.Log.WarnFormat("{0} Inventory is not locally available for agent {1} {2}",
- // MsgId, rdata.userProfile.FirstName, rdata.userProfile.SurName);
- // rdata.Fail(Rest.HttpStatusCodeNotFound, "no local inventory for user");
- //}
-
- //// If we get here, then we have successfully retrieved the user's information
- //// and inventory information is now available locally.
-
- //switch (rdata.method)
- //{
- // case Rest.HEAD : // Do the processing, set the status code, suppress entity
- // DoGet(rdata);
- // rdata.buffer = null;
- // break;
-
- // case Rest.GET : // Do the processing, set the status code, return entity
- // DoGet(rdata);
- // break;
-
- // case Rest.PUT : // Update named element
- // DoUpdate(rdata);
- // break;
-
- // case Rest.POST : // Add new information to identified context.
- // DoExtend(rdata);
- // break;
-
- // case Rest.DELETE : // Delete information
- // DoDelete(rdata);
- // break;
-
- // default :
- // Rest.Log.WarnFormat("{0} Method {1} not supported for {2}",
- // MsgId, rdata.method, rdata.path);
- // rdata.Fail(Rest.HttpStatusCodeMethodNotAllowed,
- // String.Format("{0} not supported", rdata.method));
- // break;
- //}
- }
-
- #endregion Interface
-
- #region method-specific processing
-
- ///
- /// This method implements GET processing for inventory.
- /// Any remaining parameters are used to locate the
- /// corresponding subtree based upon node name.
- ///
- /// HTTP service request work area
-// private void DoGet(InventoryRequestData rdata)
-// {
-// rdata.initXmlWriter();
-//
-// rdata.writer.WriteStartElement(String.Empty,"Inventory",String.Empty);
-//
-// // If there are additional parameters, then these represent
-// // a path relative to the root of the inventory. This path
-// // must be traversed before we format the sub-tree thus
-// // identified.
-//
-// traverse(rdata, rdata.root, PARM_PATH);
-//
-// // Close all open elements
-//
-// rdata.writer.WriteFullEndElement();
-//
-// // Indicate a successful request
-//
-// rdata.Complete();
-//
-// // Send the response to the user. The body will be implicitly
-// // constructed from the result of the XML writer.
-//
-// rdata.Respond(String.Format("Inventory {0} Normal completion", rdata.method));
-// }
-
- ///
- /// In the case of the inventory, and probably in general,
- /// the distinction between PUT and POST is not always
- /// easy to discern. The standard is badly worded in places,
- /// and adding a node to a hierarchy can be viewed as
- /// an addition, or as a modification to the inventory as
- /// a whole. This is exacerbated by an unjustified lack of
- /// consistency across different implementations.
- ///
- /// For OpenSim PUT is an update and POST is an addition. This
- /// is the behavior required by the HTTP specification and
- /// therefore as required by REST.
- ///
- /// The best way to explain the distinction is to
- /// consider the relationship between the URI and the
- /// enclosed entity. For PUT, the URI identifies the
- /// actual entity to be modified or replaced, i.e. the
- /// enclosed entity.
- ///
- /// If the operation is POST,then the URI describes the
- /// context into which the new entity will be added.
- ///
- /// As an example, suppose the URI contains:
- /// /admin/inventory/Clothing
- ///
- /// A PUT request will normally result in some modification of
- /// the folder or item named "Clothing". Whereas a POST
- /// request will normally add some new information into the
- /// content identified by Clothing. It follows from this
- /// that for POST, the element identified by the URI MUST
- /// be a folder.
- ///
-
- ///
- /// POST adds new information to the inventory in the
- /// context identified by the URI.
- ///
- /// HTTP service request work area
-// private void DoExtend(InventoryRequestData rdata)
-// {
-// bool created = false;
-// bool modified = false;
-// string newnode = String.Empty;
-//
-// // Resolve the context node specified in the URI. Entity
-// // data will be ADDED beneath this node. rdata already contains
-// // information about the current content of the user's
-// // inventory.
-//
-// Object InventoryNode = getInventoryNode(rdata, rdata.root, PARM_PATH, Rest.Fill);
-//
-// // Processing depends upon the type of inventory node
-// // identified in the URI. This is the CONTEXT for the
-// // change. We either got a context or we threw an
-// // exception.
-//
-// // It follows that we can only add information if the URI
-// // has identified a folder. So only a type of folder is supported
-// // in this case.
-//
-// if (typeof(InventoryFolderBase) == InventoryNode.GetType() ||
-// typeof(InventoryFolderImpl) == InventoryNode.GetType())
-// {
-// // Cast the context node appropriately.
-//
-// InventoryFolderBase context = (InventoryFolderBase) InventoryNode;
-//
-// Rest.Log.DebugFormat("{0} {1}: Resource(s) will be added to folder {2}",
-// MsgId, rdata.method, rdata.path);
-//
-// // Reconstitute the inventory sub-tree from the XML supplied in the entity.
-// // The result is a stand-alone inventory subtree, not yet integrated into the
-// // existing tree. An inventory collection consists of three components:
-// // [1] A (possibly empty) set of folders.
-// // [2] A (possibly empty) set of items.
-// // [3] A (possibly empty) set of assets.
-// // If all of these are empty, then the POST is a harmless no-operation.
-//
-// XmlInventoryCollection entity = ReconstituteEntity(rdata);
-//
-// // Inlined assets can be included in entity. These must be incorporated into
-// // the asset database before we attempt to update the inventory. If anything
-// // fails, return a failure to requestor.
-//
-// if (entity.Assets.Count > 0)
-// {
-// Rest.Log.DebugFormat("{0} Adding {1} assets to server",
-// MsgId, entity.Assets.Count);
-//
-// foreach (AssetBase asset in entity.Assets)
-// {
-// Rest.Log.DebugFormat("{0} Rest asset: {1} {2} {3}",
-// MsgId, asset.ID, asset.Type, asset.Name);
-// Rest.AssetServices.Store(asset);
-//
-// created = true;
-// rdata.appendStatus(String.Format(" Created asset {0}, UUID {1}
",
-// asset.Name, asset.ID));
-//
-// if (Rest.DEBUG && Rest.DumpAsset)
-// {
-// Rest.Dump(asset.Data);
-// }
-// }
-// }
-//
-// // Modify the context using the collection of folders and items
-// // returned in the XmlInventoryCollection.
-//
-// foreach (InventoryFolderBase folder in entity.Folders)
-// {
-// InventoryFolderBase found;
-//
-// // If the parentID is zero, then this folder is going
-// // into the root folder identified by the URI. The requestor
-// // may have already set the parent ID explicitly, in which
-// // case we don't have to do it here.
-//
-// if (folder.ParentID == UUID.Zero || folder.ParentID == context.ID)
-// {
-// if (newnode != String.Empty)
-// {
-// Rest.Log.DebugFormat("{0} Too many resources", MsgId);
-// rdata.Fail(Rest.HttpStatusCodeBadRequest, "only one root entity is allowed");
-// }
-// folder.ParentID = context.ID;
-// newnode = folder.Name;
-// }
-//
-// // Search the existing inventory for an existing entry. If
-// // we have one, we need to decide if it has really changed.
-// // It could just be present as (unnecessary) context, and we
-// // don't want to waste time updating the database in that
-// // case, OR, it could be being moved from another location
-// // in which case an update is most certainly necessary.
-//
-// found = null;
-//
-// foreach (InventoryFolderBase xf in rdata.folders)
-// {
-// // Compare identifying attribute
-// if (xf.ID == folder.ID)
-// {
-// found = xf;
-// break;
-// }
-// }
-//
-// if (found != null && FolderHasChanged(folder,found))
-// {
-// Rest.Log.DebugFormat("{0} Updating existing folder", MsgId);
-// Rest.InventoryServices.MoveFolder(folder);
-//
-// modified = true;
-// rdata.appendStatus(String.Format("
Created folder {0}, UUID {1}
",
-// folder.Name, folder.ID));
-// }
-// else
-// {
-// Rest.Log.DebugFormat("{0} Adding new folder", MsgId);
-// Rest.InventoryServices.AddFolder(folder);
-//
-// created = true;
-// rdata.appendStatus(String.Format("
Modified folder {0}, UUID {1}
",
-// folder.Name, folder.ID));
-// }
-// }
-//
-// // Now we repeat a similar process for the items included
-// // in the entity.
-//
-// foreach (InventoryItemBase item in entity.Items)
-// {
-// InventoryItemBase found = null;
-//
-// // If the parentID is zero, then this is going
-// // directly into the root identified by the URI.
-//
-// if (item.Folder == UUID.Zero)
-// {
-// item.Folder = context.ID;
-// }
-//
-// // Determine whether this is a new item or a
-// // replacement definition.
-//
-// foreach (InventoryItemBase xi in rdata.items)
-// {
-// // Compare identifying attribute
-// if (xi.ID == item.ID)
-// {
-// found = xi;
-// break;
-// }
-// }
-//
-// if (found != null && ItemHasChanged(item, found))
-// {
-// Rest.Log.DebugFormat("{0} Updating item {1} {2} {3} {4} {5}",
-// MsgId, item.ID, item.AssetID, item.InvType, item.AssetType, item.Name);
-// Rest.InventoryServices.UpdateItem(item);
-// modified = true;
-// rdata.appendStatus(String.Format("
Modified item {0}, UUID {1}
", item.Name, item.ID));
-// }
-// else
-// {
-// Rest.Log.DebugFormat("{0} Adding item {1} {2} {3} {4} {5}",
-// MsgId, item.ID, item.AssetID, item.InvType, item.AssetType, item.Name);
-// Rest.InventoryServices.AddItem(item);
-// created = true;
-// rdata.appendStatus(String.Format("
Created item {0}, UUID {1}
", item.Name, item.ID));
-// }
-// }
-//
-// if (created)
-// {
-// // Must include a location header with a URI that identifies the new resource.
-// rdata.AddHeader(Rest.HttpHeaderLocation,String.Format("http://{0}{1}:{2}/{3}",
-// rdata.hostname, rdata.port,rdata.path,newnode));
-// rdata.Complete(Rest.HttpStatusCodeCreated);
-// }
-// else
-// {
-// if (modified)
-// {
-// rdata.Complete(Rest.HttpStatusCodeOK);
-// }
-// else
-// {
-// rdata.Complete(Rest.HttpStatusCodeNoContent);
-// }
-// }
-//
-// rdata.Respond(String.Format("Profile {0} : Normal completion", rdata.method));
-// }
-// else
-// {
-// Rest.Log.DebugFormat("{0} {1}: Resource {2} is not a valid context: {3}",
-// MsgId, rdata.method, rdata.path, InventoryNode.GetType());
-// rdata.Fail(Rest.HttpStatusCodeBadRequest, "invalid resource context");
-// }
-// }
-
- ///
- /// PUT updates the URI-identified element in the inventory. This
- /// is actually far more flexible than it might at first sound. For
- /// PUT the URI serves two purposes:
- /// [1] It identifies the user whose inventory is to be
- /// processed.
- /// [2] It optionally specifies a subtree of the inventory
- /// that is to be used to resolve any relative subtree
- /// specifications in the entity. If nothing is specified
- /// then the whole of the private inventory is implied.
- /// Please note that the subtree specified by the URI is only relevant
- /// to an entity containing a URI relative specification, i.e. one or
- /// more elements do not specify parent folder information. These
- /// elements will be implicitly referenced within the context identified
- /// by the URI.
- /// If an element in the entity specifies an explicit parent folder, then
- /// that parent is effective, regardless of any value specified in the
- /// URI. If the parent does not exist, then the element, and any dependent
- /// elements, are ignored. This case is actually detected and handled
- /// during the reconstitution process.
- ///
- /// HTTP service request work area
-// private void DoUpdate(InventoryRequestData rdata)
-// {
-// int count = 0;
-// bool created = false;
-// bool modified = false;
-//
-// // Resolve the inventory node that is to be modified.
-// // rdata already contains information about the current
-// // content of the user's inventory.
-//
-// Object InventoryNode = getInventoryNode(rdata, rdata.root, PARM_PATH, Rest.Fill);
-//
-// // As long as we have a node, then we have something
-// // meaningful to do, unlike POST. So we reconstitute the
-// // subtree before doing anything else. Note that we
-// // etiher got a valid node or we threw an exception.
-//
-// XmlInventoryCollection entity = ReconstituteEntity(rdata);
-//
-// // Incorporate any inlined assets first. Any failures
-// // will terminate the request.
-//
-// if (entity.Assets.Count > 0)
-// {
-// Rest.Log.DebugFormat("{0} Adding {1} assets to server",
-// MsgId, entity.Assets.Count);
-//
-// foreach (AssetBase asset in entity.Assets)
-// {
-// Rest.Log.DebugFormat("{0} Rest asset: {1} {2} {3}",
-// MsgId, asset.ID, asset.Type, asset.Name);
-//
-// // The asset was validated during the collection process
-//
-// Rest.AssetServices.Store(asset);
-//
-// created = true;
-// rdata.appendStatus(String.Format("
Created asset {0}, UUID {1}
", asset.Name, asset.ID));
-//
-// if (Rest.DEBUG && Rest.DumpAsset)
-// {
-// Rest.Dump(asset.Data);
-// }
-// }
-// }
-//
-// // The URI specifies either a folder or an item to be updated.
-// //
-// // The root node in the entity will replace the node identified
-// // by the URI. This means the parent will remain the same, but
-// // any or all attributes associated with the named element
-// // will change.
-// //
-// // If the inventory collection contains an element with a zero
-// // parent ID, then this is taken to be the replacement for the
-// // named node. The collection MAY also specify an explicit
-// // parent ID, in this case it MAY identify the same parent as
-// // the current node, or it MAY specify a different parent,
-// // indicating that the folder is being moved in addition to any
-// // other modifications being made.
-//
-// if (typeof(InventoryFolderBase) == InventoryNode.GetType() ||
-// typeof(InventoryFolderImpl) == InventoryNode.GetType())
-// {
-// bool rfound = false;
-// InventoryFolderBase uri = (InventoryFolderBase) InventoryNode;
-// InventoryFolderBase xml = null;
-//
-// // If the entity to be replaced resolved to be the root
-// // directory itself (My Inventory), then make sure that
-// // the supplied data include as appropriately typed and
-// // named folder. Note that we can;t rule out the possibility
-// // of a sub-directory being called "My Inventory", so that
-// // is anticipated.
-//
-// if (uri == rdata.root)
-// {
-// foreach (InventoryFolderBase folder in entity.Folders)
-// {
-// if ((rfound = (folder.Name == PRIVATE_ROOT_NAME)))
-// {
-// if ((rfound = (folder.ParentID == UUID.Zero)))
-// break;
-// }
-// }
-//
-// if (!rfound)
-// {
-// Rest.Log.DebugFormat("{0} {1}: Path <{2}> will result in loss of inventory",
-// MsgId, rdata.method, rdata.path);
-// rdata.Fail(Rest.HttpStatusCodeBadRequest, "invalid inventory structure");
-// }
-// }
-//
-// // Scan the set of folders in the entity collection for an
-// // entry that matches the context folder. It is assumed that
-// // the only reliable indicator of this is a zero UUID (using
-// // implicit context), or the parent's UUID matches that of the
-// // URI designated node (explicit context). We don't allow
-// // ambiguity in this case because this is POST and we are
-// // supposed to be modifying a specific node.
-// // We assign any element IDs required as an economy; we don't
-// // want to iterate over the fodler set again if it can be
-// // helped.
-//
-// foreach (InventoryFolderBase folder in entity.Folders)
-// {
-// if (folder.ParentID == uri.ParentID ||
-// folder.ParentID == UUID.Zero)
-// {
-// folder.ParentID = uri.ParentID;
-// xml = folder;
-// count++;
-// }
-// }
-//
-// // More than one entry is ambiguous. Other folders should be
-// // added using the POST verb.
-//
-// if (count > 1)
-// {
-// Rest.Log.DebugFormat("{0} {1}: Request for <{2}> is ambiguous",
-// MsgId, rdata.method, rdata.path);
-// rdata.Fail(Rest.HttpStatusCodeConflict, "context is ambiguous");
-// }
-//
-// // Exactly one entry means we ARE replacing the node
-// // identified by the URI. So we delete the old folder
-// // by moving it to the trash and then purging it.
-// // We then add all of the folders and items we
-// // included in the entity. The subtree has been
-// // modified.
-//
-// if (count == 1)
-// {
-// InventoryFolderBase TrashCan = GetTrashCan(rdata);
-//
-// // All went well, so we generate a UUID is one is
-// // needed.
-//
-// if (xml.ID == UUID.Zero)
-// {
-// xml.ID = UUID.Random();
-// }
-//
-// uri.ParentID = TrashCan.ID;
-// Rest.InventoryServices.MoveFolder(uri);
-// Rest.InventoryServices.PurgeFolder(TrashCan);
-// modified = true;
-// }
-//
-// // Now, regardelss of what they represent, we
-// // integrate all of the elements in the entity.
-//
-// foreach (InventoryFolderBase f in entity.Folders)
-// {
-// rdata.appendStatus(String.Format("
Moving folder {0} UUID {1}
", f.Name, f.ID));
-// Rest.InventoryServices.MoveFolder(f);
-// }
-//
-// foreach (InventoryItemBase it in entity.Items)
-// {
-// rdata.appendStatus(String.Format("
Storing item {0} UUID {1}
", it.Name, it.ID));
-// Rest.InventoryServices.AddItem(it);
-// }
-// }
-//
-// ///
-// /// URI specifies an item to be updated
-// ///
-// ///
-// /// The entity must contain a single item node to be
-// /// updated. ID and Folder ID must be correct.
-// ///
-//
-// else
-// {
-// InventoryItemBase uri = (InventoryItemBase) InventoryNode;
-// InventoryItemBase xml = null;
-//
-// if (entity.Folders.Count != 0)
-// {
-// Rest.Log.DebugFormat("{0} {1}: Request should not contain any folders <{2}>",
-// MsgId, rdata.method, rdata.path);
-// rdata.Fail(Rest.HttpStatusCodeBadRequest, "folder is not allowed");
-// }
-//
-// if (entity.Items.Count > 1)
-// {
-// Rest.Log.DebugFormat("{0} {1}: Entity contains too many items <{2}>",
-// MsgId, rdata.method, rdata.path);
-// rdata.Fail(Rest.HttpStatusCodeBadRequest, "too may items");
-// }
-//
-// xml = entity.Items[0];
-//
-// if (xml.ID == UUID.Zero)
-// {
-// xml.ID = UUID.Random();
-// }
-//
-// // If the folder reference has changed, then this item is
-// // being moved. Otherwise we'll just delete the old, and
-// // add in the new.
-//
-// // Delete the old item
-//
-// List uuids = new List();
-// uuids.Add(uri.ID);
-// Rest.InventoryServices.DeleteItems(uri.Owner, uuids);
-//
-// // Add the new item to the inventory
-//
-// Rest.InventoryServices.AddItem(xml);
-//
-// rdata.appendStatus(String.Format("Storing item {0} UUID {1}
", xml.Name, xml.ID));
-// }
-//
-// if (created)
-// {
-// rdata.Complete(Rest.HttpStatusCodeCreated);
-// }
-// else
-// {
-// if (modified)
-// {
-// rdata.Complete(Rest.HttpStatusCodeOK);
-// }
-// else
-// {
-// rdata.Complete(Rest.HttpStatusCodeNoContent);
-// }
-// }
-//
-// rdata.Respond(String.Format("Profile {0} : Normal completion", rdata.method));
-// }
-
- ///
- /// Arguably the most damaging REST interface. It deletes the inventory
- /// item or folder identified by the URI.
- ///
- /// We only process if the URI identified node appears to exist
- /// We do not test for success because we either get a context,
- /// or an exception is thrown.
- ///
- /// Folders are deleted by moving them to another folder and then
- /// purging that folder. We'll do that by creating a temporary
- /// sub-folder in the TrashCan and purging that folder's
- /// contents. If we can't can it, we don't delete it...
- /// So, if no trashcan is available, the request does nothing.
- /// Items are summarily deleted.
- ///
- /// In the interests of safety, a delete request should normally
- /// be performed using UUID, as a name might identify several
- /// elements.
- ///
- /// HTTP service request work area
-// private void DoDelete(InventoryRequestData rdata)
-// {
-// Object InventoryNode = getInventoryNode(rdata, rdata.root, PARM_PATH, false);
-//
-// if (typeof(InventoryFolderBase) == InventoryNode.GetType() ||
-// typeof(InventoryFolderImpl) == InventoryNode.GetType())
-// {
-// InventoryFolderBase TrashCan = GetTrashCan(rdata);
-//
-// InventoryFolderBase folder = (InventoryFolderBase) InventoryNode;
-// Rest.Log.DebugFormat("{0} {1}: Folder {2} will be deleted",
-// MsgId, rdata.method, rdata.path);
-// folder.ParentID = TrashCan.ID;
-// Rest.InventoryServices.MoveFolder(folder);
-// Rest.InventoryServices.PurgeFolder(TrashCan);
-//
-// rdata.appendStatus(String.Format("
Deleted folder {0} UUID {1}
", folder.Name, folder.ID));
-// }
-//
-// // Deleting items is much more straight forward.
-//
-// else
-// {
-// InventoryItemBase item = (InventoryItemBase) InventoryNode;
-// Rest.Log.DebugFormat("{0} {1}: Item {2} will be deleted",
-// MsgId, rdata.method, rdata.path);
-// List uuids = new List();
-// uuids.Add(item.ID);
-// Rest.InventoryServices.DeleteItems(item.Owner, uuids);
-// rdata.appendStatus(String.Format("Deleted item {0} UUID {1}
", item.Name, item.ID));
-// }
-//
-// rdata.Complete();
-// rdata.Respond(String.Format("Profile {0} : Normal completion", rdata.method));
-// }
-
-#endregion method-specific processing
-
- ///
- /// This method is called to obtain the OpenSim inventory object identified
- /// by the supplied URI. This may be either an Item or a Folder, so a suitably
- /// ambiguous return type is employed (Object). This method recurses as
- /// necessary to process the designated hierarchy.
- ///
- /// If we reach the end of the URI then we return the contextual folder to
- /// our caller.
- ///
- /// If we are not yet at the end of the URI we attempt to find a child folder
- /// and if we succeed we recurse.
- ///
- /// If this is the last node, then we look to see if this is an item. If it is,
- /// we return that item.
- ///
- /// If we reach the end of an inventory path and the URI si not yet exhausted,
- /// then if 'fill' is specified, we create the intermediate nodes.
- ///
- /// Otherwise we fail the request on the ground of an invalid URI.
- ///
- /// An ambiguous request causes the request to fail.
- ///
- ///
- /// HTTP service request work area
- /// The folder to be searched (parent)
- /// URI parameter index
- /// Should missing path members be created?
-
- private Object getInventoryNode(InventoryRequestData rdata,
- InventoryFolderBase folder,
- int pi, bool fill)
- {
- InventoryFolderBase foundf = null;
- int fk = 0;
-
- Rest.Log.DebugFormat("{0} Searching folder {1} {2} [{3}]", MsgId, folder.ID, folder.Name, pi);
-
- // We have just run off the end of the parameter sequence
-
- if (pi >= rdata.Parameters.Length)
- {
- return folder;
- }
-
- // There are more names in the parameter sequence,
- // look for the folder named by param[pi] as a
- // child of the folder supplied as an argument.
- // Note that a UUID may have been supplied as the
- // identifier (it is the ONLY guaranteed unambiguous
- // option.
-
- if (rdata.folders != null)
- {
- foreach (InventoryFolderBase f in rdata.folders)
- {
- // Look for the present node in the directory list
- if (f.ParentID == folder.ID &&
- (f.Name == rdata.Parameters[pi] ||
- f.ID.ToString() == rdata.Parameters[pi]))
- {
- foundf = f;
- fk++;
- }
- }
- }
-
- // If more than one node matched, then the path, as specified
- // is ambiguous.
-
- if (fk > 1)
- {
- Rest.Log.DebugFormat("{0} {1}: Request for {2} is ambiguous",
- MsgId, rdata.method, rdata.path);
- rdata.Fail(Rest.HttpStatusCodeConflict, "request is ambiguous");
- }
-
- // If we find a match, then the method
- // increment the parameter index, and calls itself
- // passing the found folder as the new context.
-
- if (foundf != null)
- {
- return getInventoryNode(rdata, foundf, pi+1, fill);
- }
-
- // No folders that match. Perhaps this parameter identifies an item? If
- // it does, then it MUST also be the last name in the sequence.
-
- if (pi == rdata.Parameters.Length-1)
- {
- if (rdata.items != null)
- {
- int k = 0;
- InventoryItemBase li = null;
- foreach (InventoryItemBase i in rdata.items)
- {
- if (i.Folder == folder.ID &&
- (i.Name == rdata.Parameters[pi] ||
- i.ID.ToString() == rdata.Parameters[pi]))
- {
- li = i;
- k++;
- }
- }
- if (k == 1)
- {
- return li;
- }
- else if (k > 1)
- {
- Rest.Log.DebugFormat("{0} {1}: Request for {2} is ambiguous",
- MsgId, rdata.method, rdata.path);
- rdata.Fail(Rest.HttpStatusCodeConflict, "request is ambiguous");
- }
- }
- }
-
- // If fill is enabled, then we must create the missing intermediate nodes.
- // And of course, even this is not straightforward. All intermediate nodes
- // are obviously folders, but the last node may be a folder or an item.
-
- if (fill)
- {
- }
-
- // No fill, so abandon the request
-
- Rest.Log.DebugFormat("{0} {1}: Resource {2} not found",
- MsgId, rdata.method, rdata.path);
- rdata.Fail(Rest.HttpStatusCodeNotFound,
- String.Format("resource {0}:{1} not found", rdata.method, rdata.path));
-
- return null; /* Never reached */
- }
-
- ///
- /// This routine traverse the inventory's structure until the end-point identified
- /// in the URI is reached, the remainder of the inventory (if any) is then formatted
- /// and returned to the requestor.
- ///
- /// Note that this method is only interested in those folder that match elements of
- /// the URI supplied by the requestor, so once a match is fund, the processing does
- /// not need to consider any further elements.
- ///
- /// Only the last element in the URI should identify an item.
- ///
- /// HTTP service request work area
- /// The folder to be searched (parent)
- /// URI parameter index
-
- private void traverse(InventoryRequestData rdata, InventoryFolderBase folder, int pi)
- {
- Rest.Log.DebugFormat("{0} Traverse[initial] : {1} {2} [{3}]", MsgId, folder.ID, folder.Name, pi);
-
- if (rdata.folders != null)
- {
- // If there was only one parameter (avatar name), then the entire
- // inventory is being requested.
-
- if (rdata.Parameters.Length == 1)
- {
- formatInventory(rdata, rdata.root, String.Empty);
- }
-
- // Has the client specified the root directory name explicitly?
- // if yes, then we just absorb the reference, because the folder
- // we start looking in for a match *is* the root directory. If there
- // are more parameters remaining we tarverse, otehrwise it's time
- // to format. Otherwise,we consider the "My Inventory" to be implied
- // and we just traverse normally.
-
- else if (folder.ID.ToString() == rdata.Parameters[pi] ||
- folder.Name == rdata.Parameters[pi])
- {
- // Length is -1 because the avatar name is a parameter
- if (pi<(rdata.Parameters.Length-1))
- {
- traverseInventory(rdata, folder, pi+1);
- }
- else
- {
- formatInventory(rdata, folder, String.Empty);
- }
- }
- else
- {
- traverseInventory(rdata, folder, pi);
- }
-
- return;
- }
- }
-
- ///
- /// This is the recursive method. I've separated them in this way so that
- /// we do not have to waste cycles on any first-case-only processing.
- ///
-
- private void traverseInventory(InventoryRequestData rdata, InventoryFolderBase folder, int pi)
- {
- int fk = 0;
- InventoryFolderBase ffound = null;
- InventoryItemBase ifound = null;
-
- Rest.Log.DebugFormat("{0} Traverse Folder : {1} {2} [{3}]", MsgId, folder.ID, folder.Name, pi);
-
- foreach (InventoryFolderBase f in rdata.folders)
- {
- if (f.ParentID == folder.ID &&
- (f.Name == rdata.Parameters[pi] ||
- f.ID.ToString() == rdata.Parameters[pi]))
- {
- fk++;
- ffound = f;
- }
- }
-
- // If this is the last element in the parameter sequence, then
- // it is reasonable to check for an item. All intermediate nodes
- // MUST be folders.
-
- if (pi == rdata.Parameters.Length-1)
- {
- // Only if there are any items, and there pretty much always are.
-
- if (rdata.items != null)
- {
- foreach (InventoryItemBase i in rdata.items)
- {
- if (i.Folder == folder.ID &&
- (i.Name == rdata.Parameters[pi] ||
- i.ID.ToString() == rdata.Parameters[pi]))
- {
- fk++;
- ifound = i;
- }
- }
- }
- }
-
- if (fk == 1)
- {
- if (ffound != null)
- {
- if (pi < rdata.Parameters.Length-1)
- {
- traverseInventory(rdata, ffound, pi+1);
- }
- else
- {
- formatInventory(rdata, ffound, String.Empty);
- }
- return;
- }
- else
- {
- // Fetching an Item has a special significance. In this
- // case we also want to fetch the associated asset.
- // To make it interesting, we'll do this via redirection.
- string asseturl = String.Format("http://{0}:{1}/{2}{3}{4}", rdata.hostname, rdata.port,
- "admin/assets",Rest.UrlPathSeparator,ifound.AssetID.ToString());
- rdata.Redirect(asseturl,Rest.PERMANENT);
- Rest.Log.DebugFormat("{0} Never Reached", MsgId);
- }
- }
- else if (fk > 1)
- {
- rdata.Fail(Rest.HttpStatusCodeConflict,
- String.Format("ambiguous element ({0}) in path specified: <{1}>",
- pi, rdata.path));
- }
-
- Rest.Log.DebugFormat("{0} Inventory does not contain item/folder: <{1}>",
- MsgId, rdata.path);
- rdata.Fail(Rest.HttpStatusCodeNotFound,String.Format("no such item/folder : {0}",
- rdata.Parameters[pi]));
-
- }
-
- ///
- /// This method generates XML that describes an instance of InventoryFolderBase.
- /// It recurses as necessary to reflect a folder hierarchy, and calls formatItem
- /// to generate XML for any items encountered along the way.
- /// The indentation parameter is solely for the benefit of trace record
- /// formatting.
- ///
- /// HTTP service request work area
- /// The folder to be searched (parent)
- /// pretty print indentation
- private void formatInventory(InventoryRequestData rdata, InventoryFolderBase folder, string indent)
- {
- if (Rest.DEBUG)
- {
- Rest.Log.DebugFormat("{0} Folder : {1} {2} {3} type = {4}",
- MsgId, folder.ID, indent, folder.Name, folder.Type);
- indent += "\t";
- }
-
- // Start folder item
-
- rdata.writer.WriteStartElement(String.Empty,"Folder",String.Empty);
- rdata.writer.WriteAttributeString("name",String.Empty,folder.Name);
- rdata.writer.WriteAttributeString("uuid",String.Empty,folder.ID.ToString());
- rdata.writer.WriteAttributeString("parent",String.Empty,folder.ParentID.ToString());
- rdata.writer.WriteAttributeString("owner",String.Empty,folder.Owner.ToString());
- rdata.writer.WriteAttributeString("type",String.Empty,folder.Type.ToString());
- rdata.writer.WriteAttributeString("version",String.Empty,folder.Version.ToString());
-
- if (rdata.folders != null)
- {
- foreach (InventoryFolderBase f in rdata.folders)
- {
- if (f.ParentID == folder.ID)
- {
- formatInventory(rdata, f, indent);
- }
- }
- }
-
- if (rdata.items != null)
- {
- foreach (InventoryItemBase i in rdata.items)
- {
- if (i.Folder == folder.ID)
- {
- formatItem(rdata, i, indent);
- }
- }
- }
-
- // End folder item
-
- rdata.writer.WriteEndElement();
- }
-
- ///
- /// This method generates XML that describes an instance of InventoryItemBase.
- ///
- /// HTTP service request work area
- /// The item to be formatted
- /// Pretty print indentation
- private void formatItem(InventoryRequestData rdata, InventoryItemBase i, string indent)
- {
- Rest.Log.DebugFormat("{0} Item : {1} {2} {3} Type = {4}, AssetType = {5}",
- MsgId, i.ID, indent, i.Name, i.InvType, i.AssetType);
-
- rdata.writer.WriteStartElement(String.Empty, "Item", String.Empty);
-
- rdata.writer.WriteAttributeString("name", String.Empty, i.Name);
- rdata.writer.WriteAttributeString("desc", String.Empty, i.Description);
- rdata.writer.WriteAttributeString("uuid", String.Empty, i.ID.ToString());
- rdata.writer.WriteAttributeString("folder", String.Empty, i.Folder.ToString());
- rdata.writer.WriteAttributeString("owner", String.Empty, i.Owner.ToString());
- rdata.writer.WriteAttributeString("creator", String.Empty, i.CreatorId);
- rdata.writer.WriteAttributeString("creatordata", String.Empty, i.CreatorData);
- rdata.writer.WriteAttributeString("creationdate", String.Empty, i.CreationDate.ToString());
- rdata.writer.WriteAttributeString("invtype", String.Empty, i.InvType.ToString());
- rdata.writer.WriteAttributeString("assettype", String.Empty, i.AssetType.ToString());
- rdata.writer.WriteAttributeString("groupowned", String.Empty, i.GroupOwned.ToString());
- rdata.writer.WriteAttributeString("groupid", String.Empty, i.GroupID.ToString());
- rdata.writer.WriteAttributeString("saletype", String.Empty, i.SaleType.ToString());
- rdata.writer.WriteAttributeString("saleprice", String.Empty, i.SalePrice.ToString());
- rdata.writer.WriteAttributeString("flags", String.Empty, i.Flags.ToString());
-
- rdata.writer.WriteStartElement(String.Empty, "Permissions", String.Empty);
- rdata.writer.WriteAttributeString("current", String.Empty, i.CurrentPermissions.ToString("X"));
- rdata.writer.WriteAttributeString("next", String.Empty, i.NextPermissions.ToString("X"));
- rdata.writer.WriteAttributeString("group", String.Empty, i.GroupPermissions.ToString("X"));
- rdata.writer.WriteAttributeString("everyone", String.Empty, i.EveryOnePermissions.ToString("X"));
- rdata.writer.WriteAttributeString("base", String.Empty, i.BasePermissions.ToString("X"));
- rdata.writer.WriteEndElement();
-
- rdata.writer.WriteElementString("Asset", i.AssetID.ToString());
-
- rdata.writer.WriteEndElement();
- }
-
- ///
- /// This method creates a "trashcan" folder to support folder and item
- /// deletions by this interface. The xisting trash folder is found and
- /// this folder is created within it. It is called "tmp" to indicate to
- /// the client that it is OK to delete this folder. The REST interface
- /// will recreate the folder on an as-required basis.
- /// If the trash can cannot be created, then by implication the request
- /// that required it cannot be completed, and it fails accordingly.
- ///
- /// HTTP service request work area
- private InventoryFolderBase GetTrashCan(InventoryRequestData rdata)
- {
- InventoryFolderBase TrashCan = null;
-
- foreach (InventoryFolderBase f in rdata.folders)
- {
- if (f.Name == "Trash")
- {
- foreach (InventoryFolderBase t in rdata.folders)
- {
- if (t.Name == "tmp")
- {
- TrashCan = t;
- }
- }
- if (TrashCan == null)
- {
- TrashCan = new InventoryFolderBase();
- TrashCan.Name = "tmp";
- TrashCan.ID = UUID.Random();
- TrashCan.Version = 1;
- TrashCan.Type = (short) AssetType.TrashFolder;
- TrashCan.ParentID = f.ID;
- TrashCan.Owner = f.Owner;
- Rest.InventoryServices.AddFolder(TrashCan);
- }
- }
- }
-
- if (TrashCan == null)
- {
- Rest.Log.DebugFormat("{0} No Trash Can available", MsgId);
- rdata.Fail(Rest.HttpStatusCodeServerError, "unable to create trash can");
- }
-
- return TrashCan;
- }
-
- ///
- /// Make sure that an unchanged folder is not unnecessarily
- /// processed.
- ///
- /// Folder obtained from enclosed entity
- /// Folder obtained from the user's inventory
- private bool FolderHasChanged(InventoryFolderBase newf, InventoryFolderBase oldf)
- {
- return (newf.Name != oldf.Name
- || newf.ParentID != oldf.ParentID
- || newf.Owner != oldf.Owner
- || newf.Type != oldf.Type
- || newf.Version != oldf.Version
- );
- }
-
- ///
- /// Make sure that an unchanged item is not unnecessarily
- /// processed.
- ///
- /// Item obtained from enclosed entity
- /// Item obtained from the user's inventory
- private bool ItemHasChanged(InventoryItemBase newf, InventoryItemBase oldf)
- {
- return (newf.Name != oldf.Name
- || newf.Folder != oldf.Folder
- || newf.Description != oldf.Description
- || newf.Owner != oldf.Owner
- || newf.CreatorId != oldf.CreatorId
- || newf.AssetID != oldf.AssetID
- || newf.GroupID != oldf.GroupID
- || newf.GroupOwned != oldf.GroupOwned
- || newf.InvType != oldf.InvType
- || newf.AssetType != oldf.AssetType
- );
- }
-
- ///
- /// This method is called by PUT and POST to create an XmlInventoryCollection
- /// instance that reflects the content of the entity supplied on the request.
- /// Any elements in the completed collection whose UUID is zero, are
- /// considered to be located relative to the end-point identified int he
- /// URI. In this way, an entire sub-tree can be conveyed in a single REST
- /// PUT or POST request.
- ///
- /// A new instance of XmlInventoryCollection is created and, if the request
- /// has an entity, it is more completely initialized. thus, if no entity was
- /// provided the collection is valid, but empty.
- ///
- /// The entity is then scanned and each tag is processed to produce the
- /// appropriate inventory elements. At the end f the scan, teh XmlInventoryCollection
- /// will reflect the subtree described by the entity.
- ///
- /// This is a very flexible mechanism, the entity may contain arbitrary,
- /// discontiguous tree fragments, or may contain single element. The caller is
- /// responsible for integrating this collection (and ensuring that any
- /// missing parent IDs are resolved).
- ///
- /// HTTP service request work area
- internal XmlInventoryCollection ReconstituteEntity(InventoryRequestData rdata)
- {
- Rest.Log.DebugFormat("{0} Reconstituting entity", MsgId);
-
- XmlInventoryCollection ic = new XmlInventoryCollection();
-
- if (rdata.request.HasEntityBody)
- {
- Rest.Log.DebugFormat("{0} Entity present", MsgId);
-
- ic.init(rdata);
-
- try
- {
- while (ic.xml.Read())
- {
- switch (ic.xml.NodeType)
- {
- case XmlNodeType.Element:
- Rest.Log.DebugFormat("{0} StartElement: <{1}>",
- MsgId, ic.xml.Name);
-
- switch (ic.xml.Name)
- {
- case "Folder":
- Rest.Log.DebugFormat("{0} Processing {1} element",
- MsgId, ic.xml.Name);
- CollectFolder(ic);
- break;
- case "Item":
- Rest.Log.DebugFormat("{0} Processing {1} element",
- MsgId, ic.xml.Name);
- CollectItem(ic);
- break;
- case "Asset":
- Rest.Log.DebugFormat("{0} Processing {1} element",
- MsgId, ic.xml.Name);
- CollectAsset(ic);
- break;
- case "Permissions":
- Rest.Log.DebugFormat("{0} Processing {1} element",
- MsgId, ic.xml.Name);
- CollectPermissions(ic);
- break;
- default:
- Rest.Log.DebugFormat("{0} Ignoring {1} element",
- MsgId, ic.xml.Name);
- break;
- }
-
- // This stinks, but the ReadElement call above not only reads
- // the imbedded data, but also consumes the end tag for Asset
- // and moves the element pointer on to the containing Item's
- // element-end, however, if there was a permissions element
- // following, it would get us to the start of that..
- if (ic.xml.NodeType == XmlNodeType.EndElement &&
- ic.xml.Name == "Item")
- {
- Validate(ic);
- }
- break;
-
- case XmlNodeType.EndElement :
- switch (ic.xml.Name)
- {
- case "Folder":
- Rest.Log.DebugFormat("{0} Completing {1} element",
- MsgId, ic.xml.Name);
- ic.Pop();
- break;
- case "Item":
- Rest.Log.DebugFormat("{0} Completing {1} element",
- MsgId, ic.xml.Name);
- Validate(ic);
- break;
- case "Asset":
- Rest.Log.DebugFormat("{0} Completing {1} element",
- MsgId, ic.xml.Name);
- break;
- case "Permissions":
- Rest.Log.DebugFormat("{0} Completing {1} element",
- MsgId, ic.xml.Name);
- break;
- default:
- Rest.Log.DebugFormat("{0} Ignoring {1} element",
- MsgId, ic.xml.Name);
- break;
- }
- break;
-
- default:
- Rest.Log.DebugFormat("{0} Ignoring: <{1}>:<{2}>",
- MsgId, ic.xml.NodeType, ic.xml.Value);
- break;
- }
- }
- }
- catch (XmlException e)
- {
- Rest.Log.WarnFormat("{0} XML parsing error: {1}", MsgId, e.Message);
- throw e;
- }
- catch (Exception e)
- {
- Rest.Log.WarnFormat("{0} Unexpected XML parsing error: {1}", MsgId, e.Message);
- throw e;
- }
- }
- else
- {
- Rest.Log.DebugFormat("{0} Entity absent", MsgId);
- }
-
- if (Rest.DEBUG)
- {
- Rest.Log.DebugFormat("{0} Reconstituted entity", MsgId);
- Rest.Log.DebugFormat("{0} {1} assets", MsgId, ic.Assets.Count);
- Rest.Log.DebugFormat("{0} {1} folder", MsgId, ic.Folders.Count);
- Rest.Log.DebugFormat("{0} {1} items", MsgId, ic.Items.Count);
- }
-
- return ic;
- }
-
- ///
- /// This method creates an inventory Folder from the
- /// information supplied in the request's entity.
- /// A folder instance is created and initialized to reflect
- /// default values. These values are then overridden
- /// by information supplied in the entity.
- /// If context was not explicitly provided, then the
- /// appropriate ID values are determined.
- ///
-
- private void CollectFolder(XmlInventoryCollection ic)
- {
- Rest.Log.DebugFormat("{0} Interpret folder element", MsgId);
-
- InventoryFolderBase result = new InventoryFolderBase();
-
- // Default values
-
- result.Name = String.Empty;
- result.ID = UUID.Zero;
- result.Owner = ic.UserID;
- result.ParentID = UUID.Zero; // Context
- result.Type = (short) AssetType.Folder;
- result.Version = 1;
-
- if (ic.xml.HasAttributes)
- {
- for (int i = 0; i < ic.xml.AttributeCount; i++)
- {
- ic.xml.MoveToAttribute(i);
- switch (ic.xml.Name)
- {
- case "name":
- result.Name = ic.xml.Value;
- break;
- case "uuid":
- result.ID = new UUID(ic.xml.Value);
- break;
- case "parent":
- result.ParentID = new UUID(ic.xml.Value);
- break;
- case "owner":
- result.Owner = new UUID(ic.xml.Value);
- break;
- case "type":
- result.Type = Int16.Parse(ic.xml.Value);
- break;
- case "version":
- result.Version = UInt16.Parse(ic.xml.Value);
- break;
- default:
- Rest.Log.DebugFormat("{0} Folder: unrecognized attribute: {1}:{2}",
- MsgId, ic.xml.Name, ic.xml.Value);
- ic.Fail(Rest.HttpStatusCodeBadRequest, String.Format("unrecognized attribute <{0}>",
- ic.xml.Name));
- break;
- }
- }
- }
-
- ic.xml.MoveToElement();
-
- // The client is relying upon the reconstitution process
- // to determine the parent's UUID based upon context. This
- // is necessary where a new folder may have been
- // introduced.
-
- if (result.ParentID == UUID.Zero)
- {
- result.ParentID = ic.Parent();
- }
- else
- {
- bool found = false;
-
- foreach (InventoryFolderBase parent in ic.rdata.folders)
- {
- if (parent.ID == result.ParentID)
- {
- found = true;
- break;
- }
- }
-
- if (!found)
- {
- Rest.Log.ErrorFormat("{0} Invalid parent ID ({1}) in folder {2}",
- MsgId, ic.Item.Folder, result.ID);
- ic.Fail(Rest.HttpStatusCodeBadRequest, "invalid parent");
- }
- }
-
- // This is a new folder, so no existing UUID is available
- // or appropriate
-
- if (result.ID == UUID.Zero)
- {
- result.ID = UUID.Random();
- }
-
- // Treat this as a new context. Any other information is
- // obsolete as a consequence.
-
- ic.Push(result);
- }
-
- ///
- /// This method is called to handle the construction of an Item
- /// instance from the supplied request entity. It is called
- /// whenever an Item start tag is detected.
- /// An instance of an Item is created and initialized to default
- /// values. These values are then overridden from values supplied
- /// as attributes to the Item element.
- /// This item is then stored in the XmlInventoryCollection and
- /// will be verified by Validate.
- /// All context is reset whenever the effective folder changes
- /// or an item is successfully validated.
- ///
- private void CollectItem(XmlInventoryCollection ic)
- {
- Rest.Log.DebugFormat("{0} Interpret item element", MsgId);
-
- InventoryItemBase result = new InventoryItemBase();
-
- result.Name = String.Empty;
- result.Description = String.Empty;
- result.ID = UUID.Zero;
- result.Folder = UUID.Zero;
- result.Owner = ic.UserID;
- result.CreatorId = ic.UserID.ToString();
- result.AssetID = UUID.Zero;
- result.GroupID = UUID.Zero;
- result.GroupOwned = false;
- result.InvType = (int) InventoryType.Unknown;
- result.AssetType = (int) AssetType.Unknown;
-
- if (ic.xml.HasAttributes)
- {
- for (int i = 0; i < ic.xml.AttributeCount; i++)
- {
- ic.xml.MoveToAttribute(i);
-
- switch (ic.xml.Name)
- {
- case "name":
- result.Name = ic.xml.Value;
- break;
- case "desc":
- result.Description = ic.xml.Value;
- break;
- case "uuid":
- result.ID = new UUID(ic.xml.Value);
- break;
- case "folder":
- result.Folder = new UUID(ic.xml.Value);
- break;
- case "owner":
- result.Owner = new UUID(ic.xml.Value);
- break;
- case "invtype":
- result.InvType = Int32.Parse(ic.xml.Value);
- break;
- case "creator":
- result.CreatorId = ic.xml.Value;
- break;
- case "assettype":
- result.AssetType = Int32.Parse(ic.xml.Value);
- break;
- case "groupowned":
- result.GroupOwned = Boolean.Parse(ic.xml.Value);
- break;
- case "groupid":
- result.GroupID = new UUID(ic.xml.Value);
- break;
- case "flags":
- result.Flags = UInt32.Parse(ic.xml.Value);
- break;
- case "creationdate":
- result.CreationDate = Int32.Parse(ic.xml.Value);
- break;
- case "saletype":
- result.SaleType = Byte.Parse(ic.xml.Value);
- break;
- case "saleprice":
- result.SalePrice = Int32.Parse(ic.xml.Value);
- break;
-
- default:
- Rest.Log.DebugFormat("{0} Item: Unrecognized attribute: {1}:{2}",
- MsgId, ic.xml.Name, ic.xml.Value);
- ic.Fail(Rest.HttpStatusCodeBadRequest, String.Format("unrecognized attribute",
- ic.xml.Name));
- break;
- }
- }
- }
-
- ic.xml.MoveToElement();
-
- ic.Push(result);
- }
-
- ///
- /// This method assembles an asset instance from the
- /// information supplied in the request's entity. It is
- /// called as a result of detecting a start tag for a
- /// type of Asset.
- /// The information is collected locally, and an asset
- /// instance is created only if the basic XML parsing
- /// completes successfully.
- /// Default values for all parts of the asset are
- /// established before overriding them from the supplied
- /// XML.
- /// If an asset has inline=true as an attribute, then
- /// the element contains the data representing the
- /// asset. This is saved as the data component.
- /// inline=false means that the element's payload is
- /// simply the UUID of the asset referenced by the
- /// item being constructed.
- /// An asset, if created is stored in the
- /// XmlInventoryCollection
- ///
- private void CollectAsset(XmlInventoryCollection ic)
- {
- Rest.Log.DebugFormat("{0} Interpret asset element", MsgId);
-
- string name = String.Empty;
- string desc = String.Empty;
- sbyte type = (sbyte) AssetType.Unknown;
- bool temp = false;
- bool local = false;
-
- // This is not a persistent attribute
- bool inline = false;
-
- UUID uuid = UUID.Zero;
-
- // Attribute is optional
- if (ic.xml.HasAttributes)
- {
- for (int i = 0; i < ic.xml.AttributeCount; i++)
- {
- ic.xml.MoveToAttribute(i);
- switch (ic.xml.Name)
- {
- case "name" :
- name = ic.xml.Value;
- break;
-
- case "type" :
- type = SByte.Parse(ic.xml.Value);
- break;
-
- case "description" :
- desc = ic.xml.Value;
- break;
-
- case "temporary" :
- temp = Boolean.Parse(ic.xml.Value);
- break;
-
- case "uuid" :
- uuid = new UUID(ic.xml.Value);
- break;
-
- case "inline" :
- inline = Boolean.Parse(ic.xml.Value);
- break;
-
- case "local" :
- local = Boolean.Parse(ic.xml.Value);
- break;
-
- default :
- Rest.Log.DebugFormat("{0} Asset: Unrecognized attribute: {1}:{2}",
- MsgId, ic.xml.Name, ic.xml.Value);
- ic.Fail(Rest.HttpStatusCodeBadRequest,
- String.Format("unrecognized attribute <{0}>", ic.xml.Name));
- break;
- }
- }
- }
-
- ic.xml.MoveToElement();
-
- // If this is a reference to an existing asset, just store the
- // asset ID into the item.
-
- if (!inline)
- {
- if (ic.Item != null)
- {
- ic.Item.AssetID = new UUID(ic.xml.ReadElementContentAsString());
- Rest.Log.DebugFormat("{0} Asset ID supplied: {1}", MsgId, ic.Item.AssetID);
- }
- else
- {
- Rest.Log.DebugFormat("{0} LLUID unimbedded asset must be inline", MsgId);
- ic.Fail(Rest.HttpStatusCodeBadRequest, "no context for asset");
- }
- }
-
- // Otherwise, generate an asset ID, store that into the item, and
- // create an entry in the asset list for the inlined asset. But
- // only if the size is non-zero.
-
- else
- {
- AssetBase asset = null;
- string b64string = null;
-
- // Generate a UUID if none were given, and generally none should
- // be. Ever.
-
- if (uuid == UUID.Zero)
- {
- uuid = UUID.Random();
- }
-
- // Create AssetBase entity to hold the inlined asset
-
- asset = new AssetBase(uuid, name, type, UUID.Zero.ToString());
-
- asset.Description = desc;
- asset.Local = local;
- asset.Temporary = temp;
-
- b64string = ic.xml.ReadElementContentAsString();
-
- Rest.Log.DebugFormat("{0} Data length is {1}", MsgId, b64string.Length);
- Rest.Log.DebugFormat("{0} Data content starts with: \n\t<{1}>", MsgId,
- b64string.Substring(0, b64string.Length > 132 ? 132 : b64string.Length));
-
- asset.Data = Convert.FromBase64String(b64string);
-
- // Ensure the asset always has some kind of data component
-
- if (asset.Data == null)
- {
- asset.Data = new byte[1];
- }
-
- // If this is in the context of an item, establish
- // a link with the item in context.
-
- if (ic.Item != null && ic.Item.AssetID == UUID.Zero)
- {
- ic.Item.AssetID = uuid;
- }
-
- ic.Push(asset);
- }
- }
-
- ///
- /// Store any permissions information provided by the request.
- /// This overrides the default permissions set when the
- /// XmlInventoryCollection object was created.
- ///
- private void CollectPermissions(XmlInventoryCollection ic)
- {
- if (ic.xml.HasAttributes)
- {
- for (int i = 0; i < ic.xml.AttributeCount; i++)
- {
- ic.xml.MoveToAttribute(i);
- switch (ic.xml.Name)
- {
- case "current":
- ic.CurrentPermissions = UInt32.Parse(ic.xml.Value, NumberStyles.HexNumber);
- break;
- case "next":
- ic.NextPermissions = UInt32.Parse(ic.xml.Value, NumberStyles.HexNumber);
- break;
- case "group":
- ic.GroupPermissions = UInt32.Parse(ic.xml.Value, NumberStyles.HexNumber);
- break;
- case "everyone":
- ic.EveryOnePermissions = UInt32.Parse(ic.xml.Value, NumberStyles.HexNumber);
- break;
- case "base":
- ic.BasePermissions = UInt32.Parse(ic.xml.Value, NumberStyles.HexNumber);
- break;
- default:
- Rest.Log.DebugFormat("{0} Permissions: invalid attribute {1}:{2}",
- MsgId,ic.xml.Name, ic.xml.Value);
- ic.Fail(Rest.HttpStatusCodeBadRequest,
- String.Format("invalid attribute <{0}>", ic.xml.Name));
- break;
- }
- }
- }
-
- ic.xml.MoveToElement();
- }
-
- ///
- /// This method is called whenever an Item has been successfully
- /// reconstituted from the request's entity.
- /// It uses the information curren tin the XmlInventoryCollection
- /// to complete the item's specification, including any implied
- /// context and asset associations.
- /// It fails the request if any necessary item or asset information
- /// is missing.
- ///
-
- private void Validate(XmlInventoryCollection ic)
- {
- // There really should be an item present if we've
- // called validate. So fail if there is not.
-
- if (ic.Item == null)
- {
- Rest.Log.ErrorFormat("{0} Unable to parse request", MsgId);
- ic.Fail(Rest.HttpStatusCodeBadRequest, "request parse error");
- }
-
- // Every item is required to have a name (via REST anyway)
-
- if (ic.Item.Name == String.Empty)
- {
- Rest.Log.ErrorFormat("{0} An item name MUST be specified", MsgId);
- ic.Fail(Rest.HttpStatusCodeBadRequest, "item name required");
- }
-
- // An item MUST have an asset ID. AssetID should never be zero
- // here. It should always get set from the information stored
- // when the Asset element was processed.
-
- if (ic.Item.AssetID == UUID.Zero)
- {
- Rest.Log.ErrorFormat("{0} Unable to complete request", MsgId);
- Rest.Log.InfoFormat("{0} Asset information is missing", MsgId);
- ic.Fail(Rest.HttpStatusCodeBadRequest, "asset information required");
- }
-
- // If the item is new, then assign it an ID
-
- if (ic.Item.ID == UUID.Zero)
- {
- ic.Item.ID = UUID.Random();
- }
-
- // If the context is being implied, obtain the current
- // folder item's ID. If it was specified explicitly, make
- // sure that theparent folder exists.
-
- if (ic.Item.Folder == UUID.Zero)
- {
- ic.Item.Folder = ic.Parent();
- }
- else
- {
- bool found = false;
-
- foreach (InventoryFolderBase parent in ic.rdata.folders)
- {
- if (parent.ID == ic.Item.Folder)
- {
- found = true;
- break;
- }
- }
-
- if (!found)
- {
- Rest.Log.ErrorFormat("{0} Invalid parent ID ({1}) in item {2}",
- MsgId, ic.Item.Folder, ic.Item.ID);
- ic.Fail(Rest.HttpStatusCodeBadRequest, "parent information required");
- }
- }
-
- // If this is an inline asset being constructed in the context
- // of a new Item, then use the itm's name here too.
-
- if (ic.Asset != null)
- {
- if (ic.Asset.Name == String.Empty)
- ic.Asset.Name = ic.Item.Name;
- if (ic.Asset.Description == String.Empty)
- ic.Asset.Description = ic.Item.Description;
- }
-
- // Assign permissions
-
- ic.Item.CurrentPermissions = ic.CurrentPermissions;
- ic.Item.EveryOnePermissions = ic.EveryOnePermissions;
- ic.Item.BasePermissions = ic.BasePermissions;
- ic.Item.GroupPermissions = ic.GroupPermissions;
- ic.Item.NextPermissions = ic.NextPermissions;
-
- // If no type was specified for this item, we can attempt to
- // infer something from the file type maybe. This is NOT as
- // good as having type be specified in the XML.
-
- if (ic.Item.AssetType == (int) AssetType.Unknown ||
- ic.Item.InvType == (int) InventoryType.Unknown)
- {
- Rest.Log.DebugFormat("{0} Attempting to infer item type", MsgId);
-
- string[] parts = ic.Item.Name.Split(Rest.CA_PERIOD);
-
- if (Rest.DEBUG)
- {
- for (int i = 0; i < parts.Length; i++)
- {
- Rest.Log.DebugFormat("{0} Name part {1} : {2}",
- MsgId, i, parts[i]);
- }
- }
-
- // If the associated item name is multi-part, then maybe
- // the last part will indicate the item type - if we're
- // lucky.
-
- if (parts.Length > 1)
- {
- Rest.Log.DebugFormat("{0} File type is {1}",
- MsgId, parts[parts.Length - 1]);
- switch (parts[parts.Length - 1])
- {
- case "jpeg2000" :
- case "jpeg-2000" :
- case "jpg2000" :
- case "jpg-2000" :
- Rest.Log.DebugFormat("{0} Type {1} inferred",
- MsgId, parts[parts.Length-1]);
- if (ic.Item.AssetType == (int) AssetType.Unknown)
- ic.Item.AssetType = (int) AssetType.ImageJPEG;
- if (ic.Item.InvType == (int) InventoryType.Unknown)
- ic.Item.InvType = (int) InventoryType.Texture;
- break;
- case "jpg" :
- case "jpeg" :
- Rest.Log.DebugFormat("{0} Type {1} inferred",
- MsgId, parts[parts.Length - 1]);
- if (ic.Item.AssetType == (int) AssetType.Unknown)
- ic.Item.AssetType = (int) AssetType.ImageJPEG;
- if (ic.Item.InvType == (int) InventoryType.Unknown)
- ic.Item.InvType = (int) InventoryType.Texture;
- break;
- case "tga" :
- if (parts[parts.Length - 2].IndexOf("_texture") != -1)
- {
- if (ic.Item.AssetType == (int) AssetType.Unknown)
- ic.Item.AssetType = (int) AssetType.TextureTGA;
- if (ic.Item.InvType == (int) AssetType.Unknown)
- ic.Item.InvType = (int) InventoryType.Texture;
- }
- else
- {
- if (ic.Item.AssetType == (int) AssetType.Unknown)
- ic.Item.AssetType = (int) AssetType.ImageTGA;
- if (ic.Item.InvType == (int) InventoryType.Unknown)
- ic.Item.InvType = (int) InventoryType.Snapshot;
- }
- break;
- default :
- Rest.Log.DebugFormat("{0} Asset/Inventory type could not be inferred for {1}",
- MsgId,ic.Item.Name);
- break;
- }
- }
- }
-
- /// If this is a TGA remember the fact
-
- if (ic.Item.AssetType == (int) AssetType.TextureTGA ||
- ic.Item.AssetType == (int) AssetType.ImageTGA)
- {
- Bitmap temp;
- Stream tgadata = new MemoryStream(ic.Asset.Data);
-
- temp = LoadTGAClass.LoadTGA(tgadata);
- try
- {
- ic.Asset.Data = OpenJPEG.EncodeFromImage(temp, true);
- }
- catch (DllNotFoundException)
- {
- Rest.Log.ErrorFormat("OpenJpeg is not installed correctly on this system. Asset Data is empty for {0}", ic.Item.Name);
- ic.Asset.Data = new Byte[0];
- }
- catch (IndexOutOfRangeException)
- {
- Rest.Log.ErrorFormat("OpenJpeg was unable to encode this. Asset Data is empty for {0}", ic.Item.Name);
- ic.Asset.Data = new Byte[0];
- }
- catch (Exception)
- {
- Rest.Log.ErrorFormat("OpenJpeg was unable to encode this. Asset Data is empty for {0}", ic.Item.Name);
- ic.Asset.Data = new Byte[0];
- }
- }
-
- ic.reset();
- }
-
- #region Inventory RequestData extension
-
- internal class InventoryRequestData : RequestData
- {
- ///
- /// These are the inventory specific request/response state
- /// extensions.
- ///
-
- internal UUID uuid = UUID.Zero;
- internal bool HaveInventory = false;
- internal ICollection folders = null;
- internal ICollection items = null;
- internal UserProfileData userProfile = null;
- internal InventoryFolderBase root = null;
- internal bool timeout = false;
- internal Timer watchDog = new Timer();
-
- internal InventoryRequestData(OSHttpRequest request, OSHttpResponse response, string prefix)
- : base(request, response, prefix)
- {
- }
-
- internal void startWD(double interval)
- {
- Rest.Log.DebugFormat("{0} Setting watchdog", MsgId);
- watchDog.Elapsed += new ElapsedEventHandler(OnTimeOut);
- watchDog.Interval = interval;
- watchDog.AutoReset = false;
- watchDog.Enabled = true;
- lock (watchDog)
- watchDog.Start();
-
- }
-
- internal void stopWD()
- {
- Rest.Log.DebugFormat("{0} Reset watchdog", MsgId);
- lock (watchDog)
- watchDog.Stop();
- }
-
- ///
- /// This is the callback method required by the inventory watchdog. The
- /// requestor issues an inventory request and then blocks until the
- /// request completes, or this method signals the monitor.
- ///
-
- private void OnTimeOut(object sender, ElapsedEventArgs args)
- {
- Rest.Log.DebugFormat("{0} Asynchronous inventory update timed-out", MsgId);
- // InventoryRequestData rdata = (InventoryRequestData) sender;
- lock (this)
- {
- this.folders = null;
- this.items = null;
- this.HaveInventory = false;
- this.timeout = true;
- Monitor.Pulse(this);
- }
- }
-
- ///
- /// This is the callback method required by inventory services. The
- /// requestor issues an inventory request and then blocks until this
- /// method signals the monitor.
- ///
-
- internal void GetUserInventory(ICollection folders, ICollection items)
- {
- Rest.Log.DebugFormat("{0} Asynchronously updating inventory data", MsgId);
- lock (this)
- {
- if (watchDog.Enabled)
- {
- this.stopWD();
- }
- this.folders = folders;
- this.items = items;
- this.HaveInventory = true;
- this.timeout = false;
- Monitor.Pulse(this);
- }
- }
- }
-
- #endregion Inventory RequestData extension
-
- ///
- /// This class is used to record and manage the hierarchy
- /// constructed from the entity supplied in the request for
- /// PUT and POST.
- ///
-
- internal class XmlInventoryCollection : InventoryCollection
- {
- internal InventoryRequestData rdata;
- private Stack stk;
-
- internal List Assets;
-
- internal InventoryItemBase Item;
- internal AssetBase Asset;
- internal XmlReader xml;
-
- internal /*static*/ const uint DefaultCurrent = 0x7FFFFFFF;
- internal /*static*/ const uint DefaultNext = 0x82000;
- internal /*static*/ const uint DefaultBase = 0x7FFFFFFF;
- internal /*static*/ const uint DefaultEveryOne = 0x0;
- internal /*static*/ const uint DefaultGroup = 0x0;
-
- internal uint CurrentPermissions = 0x00;
- internal uint NextPermissions = 0x00;
- internal uint BasePermissions = 0x00;
- internal uint EveryOnePermissions = 0x00;
- internal uint GroupPermissions = 0x00;
-
- internal XmlInventoryCollection()
- {
- Folders = new List();
- Items = new List();
- Assets = new List();
- }
-
- internal void init(InventoryRequestData p_rdata)
- {
- rdata = p_rdata;
- UserID = rdata.uuid;
- stk = new Stack();
- rdata.initXmlReader();
- xml = rdata.reader;
- initPermissions();
- }
-
- internal void initPermissions()
- {
- CurrentPermissions = DefaultCurrent;
- NextPermissions = DefaultNext;
- BasePermissions = DefaultBase;
- GroupPermissions = DefaultGroup;
- EveryOnePermissions = DefaultEveryOne;
- }
-
- internal UUID Parent()
- {
- if (stk.Count != 0)
- {
- return stk.Peek().ID;
- }
- else
- {
- return UUID.Zero;
- }
- }
-
- internal void Push(InventoryFolderBase folder)
- {
- stk.Push(folder);
- Folders.Add(folder);
- reset();
- }
-
- internal void Push(InventoryItemBase item)
- {
- Item = item;
- Items.Add(item);
- }
-
- internal void Push(AssetBase asset)
- {
- Asset = asset;
- Assets.Add(asset);
- }
-
- internal void Pop()
- {
- stk.Pop();
- reset();
- }
-
- internal void reset()
- {
- Item = null;
- Asset = null;
- initPermissions();
- }
-
- internal void Fail(int code, string addendum)
- {
- rdata.Fail(code, addendum);
- }
- }
- }
-}
diff --git a/OpenSim/ApplicationPlugins/Rest/Inventory/RestTestServices.cs b/OpenSim/ApplicationPlugins/Rest/Inventory/RestTestServices.cs
deleted file mode 100644
index 81596a3..0000000
--- a/OpenSim/ApplicationPlugins/Rest/Inventory/RestTestServices.cs
+++ /dev/null
@@ -1,246 +0,0 @@
-/*
- * 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 OpenSimulator 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.Collections.Generic;
-using System.Reflection;
-using OpenSim.Framework.Servers;
-using OpenSim.Framework.Servers.HttpServer;
-
-namespace OpenSim.ApplicationPlugins.Rest.Inventory
-{
- public class RestTestServices : IRest
- {
- private bool enabled = false;
- private string qPrefix = "test";
-
- // A simple constructor is used to handle any once-only
- // initialization of working classes.
-
- public RestTestServices()
- {
- Rest.Log.InfoFormat("{0} Test services initializing", MsgId);
- Rest.Log.InfoFormat("{0} Using REST Implementation Version {1}", MsgId, Rest.Version);
-
- // If a relative path was specified, make it absolute by adding
- // the standard prefix, e.g. /admin
-
- if (!qPrefix.StartsWith(Rest.UrlPathSeparator))
- {
- Rest.Log.InfoFormat("{0} Domain is relative, adding absolute prefix", MsgId);
- qPrefix = String.Format("{0}{1}{2}", Rest.Prefix, Rest.UrlPathSeparator, qPrefix);
- Rest.Log.InfoFormat("{0} Domain is now <{1}>", MsgId, qPrefix);
- }
-
- // Load test cases
-
- loadTests();
- foreach (ITest test in tests)
- {
- test.Initialize();
- }
-
- // Register interface
-
- Rest.Plugin.AddPathHandler(DoTests,qPrefix,Allocate);
-
- // Activate
-
- enabled = true;
-
- Rest.Log.InfoFormat("{0} Test services initialization complete", MsgId);
- }
-
- // Post-construction, pre-enabled initialization opportunity
- // Not currently exploited.
-
- public void Initialize()
- {
- }
-
- // Called by the plug-in to halt REST processing. Local processing is
- // disabled, and control blocks until all current processing has
- // completed. No new processing will be started
-
- public void Close()
- {
- enabled = false;
- foreach (ITest test in tests)
- {
- test.Close();
- }
- Rest.Log.InfoFormat("{0} Test services closing down", MsgId);
- }
-
- // Properties
-
- internal string MsgId
- {
- get { return Rest.MsgId; }
- }
-
- #region Interface
-
- private RequestData Allocate(OSHttpRequest request, OSHttpResponse response, string prefix)
- {
- return new RequestData(request, response, prefix);
- }
-
- // Inventory Handler
-
- private void DoTests(RequestData rdata)
- {
- if (!enabled)
- return;
-
- // Now that we know this is a serious attempt to
- // access inventory data, we should find out who
- // is asking, and make sure they are authorized
- // to do so. We need to validate the caller's
- // identity before revealing anything about the
- // status quo. Authenticate throws an exception
- // via Fail if no identity information is present.
- //
- // With the present HTTP server we can't use the
- // builtin authentication mechanisms because they
- // would be enforced for all in-bound requests.
- // Instead we look at the headers ourselves and
- // handle authentication directly.
-
- try
- {
- if (!rdata.IsAuthenticated)
- {
- rdata.Fail(Rest.HttpStatusCodeNotAuthorized,
- String.Format("user \"{0}\" could not be authenticated", rdata.userName));
- }
- }
- catch (RestException e)
- {
- if (e.statusCode == Rest.HttpStatusCodeNotAuthorized)
- {
- Rest.Log.WarnFormat("{0} User not authenticated", MsgId);
- Rest.Log.DebugFormat("{0} Authorization header: {1}", MsgId, rdata.request.Headers.Get("Authorization"));
- }
- else
- {
- Rest.Log.ErrorFormat("{0} User authentication failed", MsgId);
- Rest.Log.DebugFormat("{0} Authorization header: {1}", MsgId, rdata.request.Headers.Get("Authorization"));
- }
- throw (e);
- }
-
- // Check that a test was specified
-
- if (rdata.Parameters.Length < 1)
- {
- Rest.Log.DebugFormat("{0} Insufficient parameters", MsgId);
- rdata.Fail(Rest.HttpStatusCodeBadRequest, "not enough parameters");
- }
-
- // Select the test
-
- foreach (ITest test in tests)
- {
- if (!rdata.handled)
- test.Execute(rdata);
- }
- }
-
- #endregion Interface
-
- private static bool testsLoaded = false;
- private static List classes = new List();
- private static List tests = new List();
- private static Type[] parms = new Type[0];
- private static Object[] args = new Object[0];
-
- static RestTestServices()
- {
- Module[] mods = Assembly.GetExecutingAssembly().GetModules();
- foreach (Module m in mods)
- {
- Type[] types = m.GetTypes();
- foreach (Type t in types)
- {
- try
- {
- if (t.GetInterface("ITest") != null)
- {
- classes.Add(t);
- }
- }
- catch (Exception e)
- {
- Rest.Log.WarnFormat("[STATIC-TEST] Unable to include test {0} : {1}", t, e.Message);
- }
- }
- }
- }
-
- ///
- /// This routine loads all of the handlers discovered during
- /// instance initialization. Each handler is responsible for
- /// registering itself with this handler.
- /// I was not able to make this code work in a constructor.
- ///
-
- private void loadTests()
- {
- lock (tests)
- {
- if (!testsLoaded)
- {
-
- ConstructorInfo ci;
- Object ht;
-
- foreach (Type t in classes)
- {
- try
- {
- if (t.GetInterface("ITest") != null)
- {
- ci = t.GetConstructor(parms);
- ht = ci.Invoke(args);
- tests.Add((ITest)ht);
- Rest.Log.InfoFormat("{0} Test {1} added", MsgId, t);
- }
- }
- catch (Exception e)
- {
- Rest.Log.WarnFormat("{0} Unable to load test {1} : {2}", MsgId, t, e.Message);
- }
- }
- testsLoaded = true;
- }
- }
- }
-
- }
-}
diff --git a/OpenSim/ApplicationPlugins/Rest/Inventory/tests/ITest.cs b/OpenSim/ApplicationPlugins/Rest/Inventory/tests/ITest.cs
deleted file mode 100644
index eafc154..0000000
--- a/OpenSim/ApplicationPlugins/Rest/Inventory/tests/ITest.cs
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
-* 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 OpenSimulator 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.
-*
-*/
-
-namespace OpenSim.ApplicationPlugins.Rest.Inventory
-{
-
- ///
- /// This interface represents the boundary between the general purpose
- /// REST plugin handling, and the functionally specific handlers. The
- /// handler knows only to initialzie and terminate all such handlers
- /// that it finds.
- ///
-
- internal interface ITest
- {
- void Initialize();
- void Execute(RequestData rdata);
- void Close();
- }
-
-}
diff --git a/OpenSim/ApplicationPlugins/Rest/Inventory/tests/Remote.cs b/OpenSim/ApplicationPlugins/Rest/Inventory/tests/Remote.cs
deleted file mode 100644
index 1c1afd0..0000000
--- a/OpenSim/ApplicationPlugins/Rest/Inventory/tests/Remote.cs
+++ /dev/null
@@ -1,204 +0,0 @@
-/*
- * 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 OpenSimulator 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 OpenMetaverse;
-using OpenSim.Region.Framework.Scenes;
-
-namespace OpenSim.ApplicationPlugins.Rest.Inventory.Tests
-{
- public class Remote : ITest
- {
- private static readonly int PARM_TESTID = 0;
- private static readonly int PARM_COMMAND = 1;
-
- private static readonly int PARM_MOVE_AVATAR = 2;
- private static readonly int PARM_MOVE_X = 3;
- private static readonly int PARM_MOVE_Y = 4;
- private static readonly int PARM_MOVE_Z = 5;
-
- private bool enabled = false;
-
- // No constructor code is required.
-
- public Remote()
- {
- Rest.Log.InfoFormat("{0} Remote services constructor", MsgId);
- }
-
- // Post-construction, pre-enabled initialization opportunity
- // Not currently exploited.
-
- public void Initialize()
- {
- enabled = true;
- Rest.Log.InfoFormat("{0} Remote services initialized", MsgId);
- }
-
- // Called by the plug-in to halt REST processing. Local processing is
- // disabled, and control blocks until all current processing has
- // completed. No new processing will be started
-
- public void Close()
- {
- enabled = false;
- Rest.Log.InfoFormat("{0} Remote services closing down", MsgId);
- }
-
- // Properties
-
- internal string MsgId
- {
- get { return Rest.MsgId; }
- }
-
- // Remote Handler
- // Key information of interest here is the Parameters array, each
- // entry represents an element of the URI, with element zero being
- // the
-
- public void Execute(RequestData rdata)
- {
- if (!enabled) return;
-
- // If we can't relate to what's there, leave it for others.
-
- if (rdata.Parameters.Length == 0 || rdata.Parameters[PARM_TESTID] != "remote")
- return;
-
- Rest.Log.DebugFormat("{0} REST Remote handler ENTRY", MsgId);
-
- // Remove the prefix and what's left are the parameters. If we don't have
- // the parameters we need, fail the request. Parameters do NOT include
- // any supplied query values.
-
- if (rdata.Parameters.Length > 1)
- {
- switch (rdata.Parameters[PARM_COMMAND].ToLower())
- {
- case "move" :
- DoMove(rdata);
- break;
- default :
- DoHelp(rdata);
- break;
- }
- }
- else
- {
- DoHelp(rdata);
- }
- }
-
- private void DoHelp(RequestData rdata)
- {
- rdata.body = Help;
- rdata.Complete();
- rdata.Respond("Help");
- }
-
- private void DoMove(RequestData rdata)
- {
- if (rdata.Parameters.Length < 6)
- {
- Rest.Log.WarnFormat("{0} Move: No movement information provided", MsgId);
- rdata.Fail(Rest.HttpStatusCodeBadRequest, "no movement information provided");
- }
- else
- {
- string[] names = rdata.Parameters[PARM_MOVE_AVATAR].Split(Rest.CA_SPACE);
- ScenePresence presence = null;
- Scene scene = null;
-
- if (names.Length != 2)
- {
- rdata.Fail(Rest.HttpStatusCodeBadRequest,
- String.Format("invalid avatar name: <{0}>",rdata.Parameters[PARM_MOVE_AVATAR]));
- }
-
- Rest.Log.WarnFormat("{0} '{1}' command received for {2} {3}",
- MsgId, rdata.Parameters[0], names[0], names[1]);
-
- // The first parameter should be an avatar name, look for the
- // avatar in the known regions first.
-
- Rest.main.SceneManager.ForEachScene(delegate(Scene s)
- {
- s.ForEachRootScenePresence(delegate(ScenePresence sp)
- {
- if (sp.Firstname == names[0] && sp.Lastname == names[1])
- {
- scene = s;
- presence = sp;
- }
- });
- });
-
- if (presence != null)
- {
- Rest.Log.DebugFormat("{0} Move : Avatar {1} located in region {2}",
- MsgId, rdata.Parameters[PARM_MOVE_AVATAR], scene.RegionInfo.RegionName);
-
- try
- {
- float x = Convert.ToSingle(rdata.Parameters[PARM_MOVE_X]);
- float y = Convert.ToSingle(rdata.Parameters[PARM_MOVE_Y]);
- float z = Convert.ToSingle(rdata.Parameters[PARM_MOVE_Z]);
- Vector3 vector = new Vector3(x, y, z);
- presence.MoveToTarget(vector, false, false);
- }
- catch (Exception e)
- {
- rdata.Fail(Rest.HttpStatusCodeBadRequest,
- String.Format("invalid parameters: {0}", e.Message));
- }
- }
- else
- {
- rdata.Fail(Rest.HttpStatusCodeBadRequest,
- String.Format("avatar {0} not present", rdata.Parameters[PARM_MOVE_AVATAR]));
- }
-
- rdata.Complete();
- rdata.Respond("OK");
- }
- }
-
- private static readonly string Help =
- ""
- + "Remote Command Usage"
- + ""
- + "Supported commands are:
"
- + ""
- + "- move/avatar-name/x/y/z
"
- + "- moves the specified avatar to another location
"
- + "
"
- + ""
- + ""
- ;
- }
-}
diff --git a/OpenSim/ApplicationPlugins/Rest/Regions/GETHandler.cs b/OpenSim/ApplicationPlugins/Rest/Regions/GETHandler.cs
deleted file mode 100644
index d99ba57..0000000
--- a/OpenSim/ApplicationPlugins/Rest/Regions/GETHandler.cs
+++ /dev/null
@@ -1,228 +0,0 @@
-/*
- * 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 OpenSimulator 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.IO;
-using System.Xml.Serialization;
-using OpenMetaverse;
-using OpenSim.Framework;
-using OpenSim.Framework.Servers;
-using OpenSim.Framework.Servers.HttpServer;
-using OpenSim.Region.Framework.Interfaces;
-using OpenSim.Region.Framework.Scenes;
-
-namespace OpenSim.ApplicationPlugins.Rest.Regions
-{
- public partial class RestRegionPlugin : RestPlugin
- {
- #region GET methods
- public string GetHandler(string request, string path, string param,
- IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
- {
- // foreach (string h in httpRequest.Headers.AllKeys)
- // foreach (string v in httpRequest.Headers.GetValues(h))
- // m_log.DebugFormat("{0} IsGod: {1} -> {2}", MsgID, h, v);
-
- MsgID = RequestID;
- m_log.DebugFormat("{0} GET path {1} param {2}", MsgID, path, param);
-
- try
- {
- // param empty: regions list
- if (String.IsNullOrEmpty(param)) return GetHandlerRegions(httpResponse);
-
- // param not empty: specific region
- return GetHandlerRegion(httpResponse, param);
- }
- catch (Exception e)
- {
- return Failure(httpResponse, OSHttpStatusCode.ServerErrorInternalError, "GET", e);
- }
- }
-
- public string GetHandlerRegions(IOSHttpResponse httpResponse)
- {
- RestXmlWriter rxw = new RestXmlWriter(new StringWriter());
-
- rxw.WriteStartElement(String.Empty, "regions", String.Empty);
- foreach (Scene s in App.SceneManager.Scenes)
- {
- rxw.WriteStartElement(String.Empty, "uuid", String.Empty);
- rxw.WriteString(s.RegionInfo.RegionID.ToString());
- rxw.WriteEndElement();
- }
- rxw.WriteEndElement();
-
- return rxw.ToString();
- }
-
- protected string ShortRegionInfo(string key, string value)
- {
- RestXmlWriter rxw = new RestXmlWriter(new StringWriter());
-
- if (String.IsNullOrEmpty(value) ||
- String.IsNullOrEmpty(key)) return null;
-
- rxw.WriteStartElement(String.Empty, "region", String.Empty);
- rxw.WriteStartElement(String.Empty, key, String.Empty);
- rxw.WriteString(value);
- rxw.WriteEndDocument();
-
- return rxw.ToString();
- }
-
- public string GetHandlerRegion(IOSHttpResponse httpResponse, string param)
- {
- // be resilient and don't get confused by a terminating '/'
- param = param.TrimEnd(new char[]{'/'});
- string[] comps = param.Split('/');
- UUID regionID = (UUID)comps[0];
-
- m_log.DebugFormat("{0} GET region UUID {1}", MsgID, regionID.ToString());
-
- if (UUID.Zero == regionID) throw new Exception("missing region ID");
-
- Scene scene = null;
- App.SceneManager.TryGetScene(regionID, out scene);
- if (null == scene) return Failure(httpResponse, OSHttpStatusCode.ClientErrorNotFound,
- "GET", "cannot find region {0}", regionID.ToString());
-
- 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
- RestXmlWriter rxw = new RestXmlWriter(new StringWriter());
- XmlSerializer xs = new XmlSerializer(typeof(RegionDetails));
- xs.Serialize(rxw, details, _xmlNs);
- return rxw.ToString();
- }
-
- 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(httpResponse, scene);
-
- case "stats":
- return RegionStats(httpResponse, scene);
-
- case "prims":
- return RegionPrims(httpResponse, scene, Vector3.Zero, Vector3.Zero);
- }
- }
-
- if (3 == comps.Length)
- {
- switch (comps[1].ToLower())
- {
- case "prims":
- string[] subregion = comps[2].Split(',');
- if (subregion.Length == 6)
- {
- Vector3 min, max;
- try
- {
- min = new Vector3((float)Double.Parse(subregion[0], Culture.NumberFormatInfo), (float)Double.Parse(subregion[1], Culture.NumberFormatInfo), (float)Double.Parse(subregion[2], Culture.NumberFormatInfo));
- max = new Vector3((float)Double.Parse(subregion[3], Culture.NumberFormatInfo), (float)Double.Parse(subregion[4], Culture.NumberFormatInfo), (float)Double.Parse(subregion[5], Culture.NumberFormatInfo));
- }
- catch (Exception)
- {
- return Failure(httpResponse, OSHttpStatusCode.ClientErrorBadRequest,
- "GET", "invalid subregion parameter");
- }
- return RegionPrims(httpResponse, scene, min, max);
- }
- else
- {
- return Failure(httpResponse, OSHttpStatusCode.ClientErrorBadRequest,
- "GET", "invalid subregion parameter");
- }
- }
- }
-
- return Failure(httpResponse, OSHttpStatusCode.ClientErrorBadRequest,
- "GET", "too many parameters {0}", param);
- }
- #endregion GET methods
-
- protected string RegionTerrain(IOSHttpResponse httpResponse, Scene scene)
- {
- httpResponse.SendChunked = true;
- httpResponse.ContentType = "text/xml";
-
- return scene.Heightmap.SaveToXmlString();
- //return Failure(httpResponse, OSHttpStatusCode.ServerErrorNotImplemented,
- // "GET", "terrain not implemented");
- }
-
- protected string RegionStats(IOSHttpResponse httpResponse, Scene scene)
- {
- int users = scene.GetRootAgentCount();
- int objects = scene.Entities.Count - users;
-
- RestXmlWriter rxw = new RestXmlWriter(new StringWriter());
-
- rxw.WriteStartElement(String.Empty, "region", String.Empty);
- rxw.WriteStartElement(String.Empty, "stats", String.Empty);
-
- rxw.WriteStartElement(String.Empty, "users", String.Empty);
- rxw.WriteString(users.ToString());
- rxw.WriteEndElement();
-
- rxw.WriteStartElement(String.Empty, "objects", String.Empty);
- rxw.WriteString(objects.ToString());
- rxw.WriteEndElement();
-
- rxw.WriteEndDocument();
-
- return rxw.ToString();
- }
-
- protected string RegionPrims(IOSHttpResponse httpResponse, Scene scene, Vector3 min, Vector3 max)
- {
- httpResponse.SendChunked = true;
- httpResponse.ContentType = "text/xml";
-
- IRegionSerialiserModule serialiser = scene.RequestModuleInterface();
- if (serialiser != null)
- serialiser.SavePrimsToXml2(scene, new StreamWriter(httpResponse.OutputStream), min, max);
-
- return "";
- }
- }
-}
diff --git a/OpenSim/ApplicationPlugins/Rest/Regions/GETRegionInfoHandler.cs b/OpenSim/ApplicationPlugins/Rest/Regions/GETRegionInfoHandler.cs
deleted file mode 100644
index 468faea..0000000
--- a/OpenSim/ApplicationPlugins/Rest/Regions/GETRegionInfoHandler.cs
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- * 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 OpenSimulator 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.IO;
-using System.Xml.Serialization;
-using OpenMetaverse;
-using OpenSim.Framework.Servers;
-using OpenSim.Framework.Servers.HttpServer;
-using OpenSim.Region.Framework.Interfaces;
-using OpenSim.Region.Framework.Scenes;
-
-namespace OpenSim.ApplicationPlugins.Rest.Regions
-{
- public partial class RestRegionPlugin : RestPlugin
- {
- #region GET methods
- public string GetRegionInfoHandler(string request, string path, string param,
- IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
- {
- // foreach (string h in httpRequest.Headers.AllKeys)
- // foreach (string v in httpRequest.Headers.GetValues(h))
- // m_log.DebugFormat("{0} IsGod: {1} -> {2}", MsgID, h, v);
-
- MsgID = RequestID;
- m_log.DebugFormat("{0} GET path {1} param {2}", MsgID, path, param);
-
- try
- {
- // param empty: regions list
- // if (String.IsNullOrEmpty(param))
- return GetRegionInfoHandlerRegions(httpResponse);
-
- // // param not empty: specific region
- // return GetRegionInfoHandlerRegion(httpResponse, param);
- }
- catch (Exception e)
- {
- return Failure(httpResponse, OSHttpStatusCode.ServerErrorInternalError, "GET", e);
- }
- }
-
- public string GetRegionInfoHandlerRegions(IOSHttpResponse httpResponse)
- {
- RestXmlWriter rxw = new RestXmlWriter(new StringWriter());
-
- // regions info
- rxw.WriteStartElement(String.Empty, "regions", String.Empty);
- {
- // regions info: number of regions
- rxw.WriteStartAttribute(String.Empty, "number", String.Empty);
- rxw.WriteValue(App.SceneManager.Scenes.Count);
- rxw.WriteEndAttribute();
-
- // regions info: max number of regions
- rxw.WriteStartAttribute(String.Empty, "max", String.Empty);
- if (App.ConfigSource.Source.Configs["RemoteAdmin"] != null)
- {
- rxw.WriteValue(App.ConfigSource.Source.Configs["RemoteAdmin"].GetInt("region_limit", -1));
- }
- else
- {
- rxw.WriteValue(-1);
- }
- rxw.WriteEndAttribute();
-
- // regions info: region
- foreach (Scene s in App.SceneManager.Scenes)
- {
- rxw.WriteStartElement(String.Empty, "region", String.Empty);
-
- rxw.WriteStartAttribute(String.Empty, "uuid", String.Empty);
- rxw.WriteString(s.RegionInfo.RegionID.ToString());
- rxw.WriteEndAttribute();
-
- rxw.WriteStartAttribute(String.Empty, "name", String.Empty);
- rxw.WriteString(s.RegionInfo.RegionName);
- rxw.WriteEndAttribute();
-
- rxw.WriteStartAttribute(String.Empty, "x", String.Empty);
- rxw.WriteValue(s.RegionInfo.RegionLocX);
- rxw.WriteEndAttribute();
-
- rxw.WriteStartAttribute(String.Empty, "y", String.Empty);
- rxw.WriteValue(s.RegionInfo.RegionLocY);
- rxw.WriteEndAttribute();
-
- rxw.WriteStartAttribute(String.Empty, "external_hostname", String.Empty);
- rxw.WriteString(s.RegionInfo.ExternalHostName);
- rxw.WriteEndAttribute();
-
- rxw.WriteStartAttribute(String.Empty, "ip", String.Empty);
- rxw.WriteString(s.RegionInfo.InternalEndPoint.ToString());
- rxw.WriteEndAttribute();
-
- int users = s.GetRootAgentCount();
- rxw.WriteStartAttribute(String.Empty, "avatars", String.Empty);
- rxw.WriteValue(users);
- rxw.WriteEndAttribute();
-
- rxw.WriteStartAttribute(String.Empty, "objects", String.Empty);
- rxw.WriteValue(s.Entities.Count - users);
- rxw.WriteEndAttribute();
-
- rxw.WriteEndElement();
- }
- }
- return rxw.ToString();
- }
- #endregion GET methods
- }
-}
diff --git a/OpenSim/ApplicationPlugins/Rest/Regions/POSTHandler.cs b/OpenSim/ApplicationPlugins/Rest/Regions/POSTHandler.cs
deleted file mode 100644
index f666f45..0000000
--- a/OpenSim/ApplicationPlugins/Rest/Regions/POSTHandler.cs
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * 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 OpenSimulator 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.IO;
-using OpenMetaverse;
-using OpenSim.Framework.Servers;
-using OpenSim.Framework.Servers.HttpServer;
-using OpenSim.Region.Framework.Interfaces;
-using OpenSim.Region.Framework.Scenes;
-
-namespace OpenSim.ApplicationPlugins.Rest.Regions
-{
- public partial class RestRegionPlugin : RestPlugin
- {
- #region POST methods
-
- public string PostHandler(string request, string path, string param,
- IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
- {
- // foreach (string h in httpRequest.Headers.AllKeys)
- // foreach (string v in httpRequest.Headers.GetValues(h))
- // m_log.DebugFormat("{0} IsGod: {1} -> {2}", MsgID, h, v);
-
- MsgID = RequestID;
- m_log.DebugFormat("{0} POST path {1} param {2}", MsgID, path, param);
-
- try
- {
- // param empty: new region post
- if (!IsGod(httpRequest))
- // XXX: this needs to be turned into a FailureUnauthorized(...)
- return Failure(httpResponse, OSHttpStatusCode.ClientErrorUnauthorized,
- "GET", "you are not god");
-
- if (String.IsNullOrEmpty(param)) return CreateRegion(httpRequest, httpResponse);
-
- // Parse region ID and other parameters
- param = param.TrimEnd(new char[] {'/'});
- string[] comps = param.Split('/');
- UUID regionID = (UUID) comps[0];
-
- m_log.DebugFormat("{0} POST region UUID {1}", MsgID, regionID.ToString());
- if (UUID.Zero == regionID) throw new Exception("missing region ID");
-
- Scene scene = null;
- App.SceneManager.TryGetScene(regionID, out scene);
- if (null == scene)
- return Failure(httpResponse, OSHttpStatusCode.ClientErrorNotFound,
- "POST", "cannot find region {0}", regionID.ToString());
-
- if (2 == comps.Length)
- {
- // check for {prims}
- switch (comps[1].ToLower())
- {
- case "prims":
- return LoadPrims(request, httpRequest, httpResponse, scene);
- }
- }
-
- return Failure(httpResponse, OSHttpStatusCode.ClientErrorNotFound,
- "POST", "url {0} not supported", param);
- }
- catch (Exception e)
- {
- return Failure(httpResponse, OSHttpStatusCode.ServerErrorInternalError, "POST", e);
- }
- }
-
- public string CreateRegion(IOSHttpRequest request, IOSHttpResponse response)
- {
- RestXmlWriter rxw = new RestXmlWriter(new StringWriter());
-
- rxw.WriteStartElement(String.Empty, "regions", String.Empty);
- foreach (Scene s in App.SceneManager.Scenes)
- {
- rxw.WriteStartElement(String.Empty, "uuid", String.Empty);
- rxw.WriteString(s.RegionInfo.RegionID.ToString());
- rxw.WriteEndElement();
- }
- rxw.WriteEndElement();
-
- return rxw.ToString();
- }
-
- public string LoadPrims(string requestBody, IOSHttpRequest request, IOSHttpResponse response, Scene scene)
- {
- IRegionSerialiserModule serialiser = scene.RequestModuleInterface();
- if (serialiser != null)
- serialiser.LoadPrimsFromXml2(scene, new StringReader(requestBody), true);
-
- return "";
- }
-
- #endregion POST methods
- }
-}
diff --git a/OpenSim/ApplicationPlugins/Rest/Regions/RegionDetails.cs b/OpenSim/ApplicationPlugins/Rest/Regions/RegionDetails.cs
deleted file mode 100644
index 5e76009..0000000
--- a/OpenSim/ApplicationPlugins/Rest/Regions/RegionDetails.cs
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * 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 OpenSimulator 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.Xml.Serialization;
-using OpenMetaverse;
-using OpenSim.Framework;
-
-namespace OpenSim.ApplicationPlugins.Rest.Regions
-{
- [XmlRoot(ElementName="region", IsNullable = false)]
- public class RegionDetails
- {
- public string region_name;
- public string region_id;
- public uint region_x;
- public uint region_y;
- public string region_owner;
- public string region_owner_id;
- public uint region_http_port;
- public uint region_port;
- public string region_server_uri;
- public string region_external_hostname;
-
- public RegionDetails()
- {
- }
-
- public RegionDetails(RegionInfo regInfo)
- {
- region_name = regInfo.RegionName;
- region_id = regInfo.RegionID.ToString();
- region_x = regInfo.RegionLocX;
- region_y = regInfo.RegionLocY;
- region_owner_id = regInfo.EstateSettings.EstateOwner.ToString();
- region_http_port = regInfo.HttpPort;
- region_server_uri = regInfo.ServerURI;
- region_external_hostname = regInfo.ExternalHostName;
-
- Uri uri = new Uri(region_server_uri);
- region_port = (uint)uri.Port;
- }
-
- 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;
- }
- }
- }
- }
-}
diff --git a/OpenSim/ApplicationPlugins/Rest/Regions/Resources/RestRegionPlugin.addin.xml b/OpenSim/ApplicationPlugins/Rest/Regions/Resources/RestRegionPlugin.addin.xml
deleted file mode 100644
index 94eca48..0000000
--- a/OpenSim/ApplicationPlugins/Rest/Regions/Resources/RestRegionPlugin.addin.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
diff --git a/OpenSim/ApplicationPlugins/Rest/Regions/RestRegionPlugin.cs b/OpenSim/ApplicationPlugins/Rest/Regions/RestRegionPlugin.cs
deleted file mode 100644
index 02ef588..0000000
--- a/OpenSim/ApplicationPlugins/Rest/Regions/RestRegionPlugin.cs
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * 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 OpenSimulator 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.Xml.Serialization;
-
-namespace OpenSim.ApplicationPlugins.Rest.Regions
-{
- public partial class RestRegionPlugin : RestPlugin
- {
- private static XmlSerializerNamespaces _xmlNs;
-
- static RestRegionPlugin()
- {
- _xmlNs = new XmlSerializerNamespaces();
- _xmlNs.Add(String.Empty, String.Empty);
- }
-
- #region overriding properties
- public override string Name
- {
- get { return "REGION"; }
- }
-
- public override string ConfigName
- {
- get { return "RestRegionPlugin"; }
- }
- #endregion overriding properties
-
- #region overriding methods
- ///
- /// This method is called by OpenSimMain immediately after loading the
- /// plugin and after basic server setup, but before running any server commands.
- ///
- ///
- /// Note that entries MUST be added to the active configuration files before
- /// the plugin can be enabled.
- ///
- public override void Initialise(OpenSimBase openSim)
- {
- try
- {
- base.Initialise(openSim);
- 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);
- AddRestStreamHandler("POST", "/regions/", PostHandler);
- AddRestStreamHandler("GET", "/regioninfo/", GetRegionInfoHandler);
- }
- catch (Exception e)
- {
- m_log.WarnFormat("{0} Initialization failed: {1}", MsgID, e.Message);
- m_log.DebugFormat("{0} Initialization failed: {1}", MsgID, e.ToString());
- }
- }
-
- public override void Close()
- {
- }
- #endregion overriding methods
- }
-}
diff --git a/OpenSim/ApplicationPlugins/Rest/RestPlugin.cs b/OpenSim/ApplicationPlugins/Rest/RestPlugin.cs
deleted file mode 100644
index a2425b5..0000000
--- a/OpenSim/ApplicationPlugins/Rest/RestPlugin.cs
+++ /dev/null
@@ -1,417 +0,0 @@
-/*
- * 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 OpenSimulator 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.Collections.Generic;
-using System.IO;
-using System.Reflection;
-using System.Xml;
-using log4net;
-using Nini.Config;
-using OpenMetaverse;
-using OpenSim.Framework;
-using OpenSim.Framework.Servers;
-using OpenSim.Framework.Servers.HttpServer;
-
-namespace OpenSim.ApplicationPlugins.Rest
-{
- public abstract class RestPlugin : IApplicationPlugin
- {
- #region properties
-
- protected static readonly ILog m_log =
- LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
-
- private IConfig _config; // Configuration source: Rest Plugins
- private IConfig _pluginConfig; // Configuration source: Plugin specific
- private OpenSimBase _app; // The 'server'
- private BaseHttpServer _httpd; // The server's RPC interface
- private string _prefix; // URL prefix below
- // which all REST URLs
- // are living
- // private StringWriter _sw = null;
- // private RestXmlWriter _xw = null;
-
- private string _godkey;
- private int _reqk;
-
- [ThreadStatic]
- private static string _threadRequestID = String.Empty;
-
- ///
- /// Return an ever increasing request ID for logging
- ///
- protected string RequestID
- {
- get { return _reqk++.ToString(); }
- set { _reqk = Convert.ToInt32(value); }
- }
-
- ///
- /// Thread-constant message IDs for logging.
- ///
- protected string MsgID
- {
- get { return String.Format("[REST-{0}] #{1}", Name, _threadRequestID); }
- set { _threadRequestID = value; }
- }
-
- ///
- /// Returns true if Rest Plugins are enabled.
- ///
- public bool PluginsAreEnabled
- {
- get { return null != _config; }
- }
-
- ///
- /// Returns true if specific Rest Plugin is enabled.
- ///
- public bool IsEnabled
- {
- get
- {
- return (null != _pluginConfig) && _pluginConfig.GetBoolean("enabled", false);
- }
- }
-
- ///
- /// OpenSimMain application
- ///
- public OpenSimBase App
- {
- get { return _app; }
- }
-
- ///
- /// RPC server
- ///
- public BaseHttpServer HttpServer
- {
- get { return _httpd; }
- }
-
- ///
- /// URL prefix to use for all REST handlers
- ///
- public string Prefix
- {
- get { return _prefix; }
- }
-
- ///
- /// Access to GOD password string
- ///
- protected string GodKey
- {
- get { return _godkey; }
- }
-
- ///
- /// Configuration of the plugin
- ///
- public IConfig Config
- {
- get { return _pluginConfig; }
- }
-
- ///
- /// Name of the plugin
- ///
- public abstract string Name { get; }
-
- ///
- /// Return the config section name
- ///
- public abstract string ConfigName { get; }
-
- // public XmlTextWriter XmlWriter
- // {
- // get
- // {
- // if (null == _xw)
- // {
- // _sw = new StringWriter();
- // _xw = new RestXmlWriter(_sw);
- // _xw.Formatting = Formatting.Indented;
- // }
- // return _xw;
- // }
- // }
-
- // public string XmlWriterResult
- // {
- // get
- // {
- // _xw.Flush();
- // _xw.Close();
- // _xw = null;
-
- // return _sw.ToString();
- // }
- // }
-
- #endregion properties
-
- #region methods
-
- // TODO: required by IPlugin, but likely not at all right
- private string m_version = "0.0";
-
- public string Version
- {
- get { return m_version; }
- }
-
- public void Initialise()
- {
- m_log.Info("[RESTPLUGIN]: " + Name + " cannot be default-initialized!");
- throw new PluginNotInitialisedException(Name);
- }
-
- ///
- /// This method is called by OpenSimMain immediately after loading the
- /// plugin and after basic server setup, but before running any server commands.
- ///
- ///
- /// Note that entries MUST be added to the active configuration files before
- /// the plugin can be enabled.
- ///
- public virtual void Initialise(OpenSimBase openSim)
- {
- RequestID = "0";
- MsgID = RequestID;
-
- try
- {
- if ((_config = openSim.ConfigSource.Source.Configs["RestPlugins"]) == null)
- {
- m_log.WarnFormat("{0} Rest Plugins not configured", MsgID);
- return;
- }
-
- if (!_config.GetBoolean("enabled", false))
- {
- //m_log.WarnFormat("{0} Rest Plugins are disabled", MsgID);
- return;
- }
-
- _app = openSim;
- _httpd = openSim.HttpServer;
-
- // Retrieve GOD key value, if any.
- _godkey = _config.GetString("god_key", String.Empty);
-
- // Retrive prefix if any.
- _prefix = _config.GetString("prefix", "/admin");
-
- // Get plugin specific config
- _pluginConfig = openSim.ConfigSource.Source.Configs[ConfigName];
-
- m_log.InfoFormat("{0} Rest Plugins Enabled", MsgID);
- }
- catch (Exception e)
- {
- // we can safely ignore this, as it just means that
- // the key lookup in Configs failed, which signals to
- // us that noone is interested in our services...they
- // don't know what they are missing out on...
- // NOTE: Under the present OpenSimulator implementation it is
- // not possible for the openSimulator 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
- // diagnostic indication as to why. The same is true if
- // the HTTP server reference is bad.
- // We should at least issue a message...
- m_log.WarnFormat("{0} Initialization failed: {1}", MsgID, e.Message);
- m_log.DebugFormat("{0} Initialization failed: {1}", MsgID, e.ToString());
- }
- }
-
- public virtual void PostInitialise()
- {
- }
-
- private List _handlers = new List();
- private Dictionary _agents = new Dictionary();
-
- ///
- /// Add a REST stream handler to the underlying HTTP server.
- ///
- /// GET/PUT/POST/DELETE or
- /// similar
- /// URL prefix
- /// RestMethod handler doing the actual work
- public virtual void AddRestStreamHandler(string httpMethod, string path, RestMethod method)
- {
- if (!IsEnabled) return;
-
- if (!path.StartsWith(_prefix))
- {
- path = String.Format("{0}{1}", _prefix, path);
- }
-
- RestStreamHandler h = new RestStreamHandler(httpMethod, path, method);
- _httpd.AddStreamHandler(h);
- _handlers.Add(h);
-
- m_log.DebugFormat("{0} Added REST handler {1} {2}", MsgID, httpMethod, path);
- }
-
- ///
- /// Add a powerful Agent handler to the underlying HTTP
- /// server.
- ///
- /// name of agent handler
- /// agent handler method
- /// false when the plugin is disabled or the agent
- /// handler could not be added. Any generated exceptions are
- /// allowed to drop through to the caller, i.e. ArgumentException.
- ///
- public bool AddAgentHandler(string agentName, IHttpAgentHandler handler)
- {
- if (!IsEnabled) return false;
- _agents.Add(agentName, handler);
-// return _httpd.AddAgentHandler(agentName, handler);
-
- return false;
- }
-
- ///
- /// Remove a powerful Agent handler from the underlying HTTP
- /// server.
- ///
- /// name of agent handler
- /// agent handler method
- /// false when the plugin is disabled or the agent
- /// handler could not be removed. Any generated exceptions are
- /// allowed to drop through to the caller, i.e. KeyNotFound.
- ///
- public bool RemoveAgentHandler(string agentName, IHttpAgentHandler handler)
- {
- if (!IsEnabled) return false;
- if (_agents[agentName] == handler)
- {
- _agents.Remove(agentName);
-// return _httpd.RemoveAgentHandler(agentName, handler);
- }
- return false;
- }
-
- ///
- /// Check whether the HTTP request came from god; that is, is
- /// the god_key as configured in the config section supplied
- /// via X-OpenSim-Godkey?
- ///
- /// HTTP request header
- /// true when the HTTP request came from god.
- protected bool IsGod(IOSHttpRequest request)
- {
- string[] keys = request.Headers.GetValues("X-OpenSim-Godkey");
- if (null == keys) return false;
-
- // we take the last key supplied
- return keys[keys.Length - 1] == _godkey;
- }
-
- ///
- /// Checks wether the X-OpenSim-Password value provided in the
- /// HTTP header is indeed the password on file for the avatar
- /// specified by the UUID
- ///
- protected bool IsVerifiedUser(IOSHttpRequest request, UUID uuid)
- {
- // XXX under construction
- return false;
- }
-
- ///
- /// Clean up and remove all handlers that were added earlier.
- ///
- public virtual void Close()
- {
- foreach (RestStreamHandler h in _handlers)
- {
- _httpd.RemoveStreamHandler(h.HttpMethod, h.Path);
- }
- _handlers = null;
-// foreach (KeyValuePair h in _agents)
-// {
-// _httpd.RemoveAgentHandler(h.Key, h.Value);
-// }
- _agents = null;
- }
-
- public virtual void Dispose()
- {
- Close();
- }
-
- ///
- /// Return a failure message.
- ///
- /// origin of the failure message
- /// failure message
- /// This should probably set a return code as
- /// well. (?)
- protected string Failure(IOSHttpResponse response, OSHttpStatusCode status,
- string method, string format, params string[] msg)
- {
- string m = String.Format(format, msg);
-
- response.StatusCode = (int) status;
- response.StatusDescription = m;
-
- m_log.ErrorFormat("{0} {1} failed: {2}", MsgID, method, m);
- return String.Format("{0}", m);
- }
-
- ///
- /// Return a failure message.
- ///
- /// origin of the failure message
- /// exception causing the failure message
- /// This should probably set a return code as
- /// well. (?)
- public string Failure(IOSHttpResponse response, OSHttpStatusCode status,
- string method, Exception e)
- {
- string m = String.Format("exception occurred: {0}", e.Message);
-
- response.StatusCode = (int) status;
- response.StatusDescription = m;
-
- 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
- }
-}
diff --git a/OpenSim/ApplicationPlugins/Rest/RestXmlWriter.cs b/OpenSim/ApplicationPlugins/Rest/RestXmlWriter.cs
deleted file mode 100644
index 283fa2e..0000000
--- a/OpenSim/ApplicationPlugins/Rest/RestXmlWriter.cs
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * 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 OpenSimulator 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.IO;
-using System.Text;
-using System.Xml;
-
-namespace OpenSim.ApplicationPlugins.Rest
-{
- public class RestXmlWriter: XmlTextWriter
- {
- private StringWriter m_sw = null;
-
- public RestXmlWriter(StringWriter sw) : base(sw)
- {
- m_sw = sw;
- Formatting = Formatting.Indented;
- }
-
- public RestXmlWriter(TextWriter textWriter) : base(textWriter)
- {
- }
-
- public RestXmlWriter(Stream stream)
- : this(stream, Encoding.UTF8)
- {
- }
-
- public RestXmlWriter(Stream stream, Encoding enc) : base(stream, enc)
- {
- }
-
- public override void WriteStartDocument()
- {
- }
-
- public override void WriteStartDocument(bool standalone)
- {
- }
-
- public override string ToString()
- {
- Flush();
- Close();
- return m_sw.ToString();
- }
- }
-}
diff --git a/OpenSim/ApplicationPlugins/Rest/rest.xsd b/OpenSim/ApplicationPlugins/Rest/rest.xsd
deleted file mode 100644
index 4dc0ae4..0000000
--- a/OpenSim/ApplicationPlugins/Rest/rest.xsd
+++ /dev/null
@@ -1,276 +0,0 @@
-
-
-
-
- Open Simulator Export/Import XML schema
- August 2008
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
--
cgit v1.1
From 6e1b3f9951b5ae9fbc0dc65e8404cb878206c68d Mon Sep 17 00:00:00 2001
From: teravus
Date: Sat, 16 Mar 2013 03:14:11 -0400
Subject: *Yet another HTTPServer update code changes in OpenSim Libs. * This
fixes a connection close issue by getting rid of the socket references *
This adds a connection timeout checker to shutdown poor or evil connections
and combats DOS attempts that just connect and make no complete requests and
just wait. It also actually implements KeepAlive... instead of just
understanding the connection header in the request... you can test by
connecting and requesting a keepalive header and sending another request on
the same connection. The new timeout checker closes expired keepalive
sessions, just make sure you send the request within 70 seconds of connecting
or the timeout checker will timeout the connection.
---
OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs | 17 ++++++++++++++---
1 file changed, 14 insertions(+), 3 deletions(-)
(limited to 'OpenSim')
diff --git a/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs b/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs
index 58312ab..dfdd566 100644
--- a/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs
+++ b/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs
@@ -486,7 +486,9 @@ namespace OpenSim.Framework.Servers.HttpServer
{
try
{
- SendHTML500(response);
+ byte[] buffer500 = SendHTML500(response);
+ response.Body.Write(buffer500,0,buffer500.Length);
+ response.Body.Close();
}
catch
{
@@ -719,7 +721,15 @@ namespace OpenSim.Framework.Servers.HttpServer
catch (Exception e)
{
m_log.Error(String.Format("[BASE HTTP SERVER]: HandleRequest() threw {0} ", e.StackTrace), e);
- SendHTML500(response);
+ try
+ {
+ byte[] buffer500 = SendHTML500(response);
+ response.Body.Write(buffer500, 0, buffer500.Length);
+ response.Body.Close();
+ }
+ catch
+ {
+ }
}
finally
{
@@ -1746,7 +1756,8 @@ namespace OpenSim.Framework.Servers.HttpServer
response.SendChunked = false;
response.ContentLength64 = buffer.Length;
response.ContentEncoding = Encoding.UTF8;
-
+
+
return buffer;
}
--
cgit v1.1
From fc84ebb819b590099bbfa5bd357e886ce7460063 Mon Sep 17 00:00:00 2001
From: Vegaslon
Date: Sat, 16 Mar 2013 17:16:01 -0400
Subject: BulletSim: Working Implementation of Angular Banking for Vehicles
(Not SL Grade, Other features when implemented should slow it down for now be
Strong with Vertical Angular attraction setting and conservative with Angular
Velocity on X axis)
Signed-off-by: Robert Adams
---
OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs | 33 +++++++++++-----------
1 file changed, 17 insertions(+), 16 deletions(-)
(limited to 'OpenSim')
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
index d347159..96eaa6b 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
@@ -143,7 +143,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
{
enableAngularVerticalAttraction = true;
enableAngularDeflection = false;
- enableAngularBanking = false;
+ enableAngularBanking = true;
if (BSParam.VehicleDebuggingEnabled)
{
enableAngularVerticalAttraction = true;
@@ -1280,11 +1280,11 @@ namespace OpenSim.Region.Physics.BulletSPlugin
// That is, NO_DEFLECTION_UP says angular motion should not add any pitch or roll movement
// TODO: This is here because this is where ODE put it but documentation says it
// is a linear effect. Where should this check go?
- if ((m_flags & (VehicleFlag.NO_DEFLECTION_UP)) != 0)
- {
- angularMotorContributionV.X = 0f;
- angularMotorContributionV.Y = 0f;
- }
+ //if ((m_flags & (VehicleFlag.NO_DEFLECTION_UP)) != 0)
+ // {
+ // angularMotorContributionV.X = 0f;
+ // angularMotorContributionV.Y = 0f;
+ // }
VehicleRotationalVelocity += angularMotorContributionV * VehicleOrientation;
VDetailLog("{0}, MoveAngular,angularTurning,angularMotorContrib={1}", Prim.LocalID, angularMotorContributionV);
@@ -1437,24 +1437,25 @@ namespace OpenSim.Region.Physics.BulletSPlugin
// As the vehicle rolls to the right or left, the Y value will increase from
// zero (straight up) to 1 or -1 (full tilt right or left)
Vector3 rollComponents = Vector3.UnitZ * VehicleOrientation;
-
// Figure out the yaw value for this much roll.
// Squared because that seems to give a good value
- float yawAngle = (float)Math.Asin(rollComponents.Y * rollComponents.Y) * m_bankingEfficiency;
-
+ // float yawAngle = (float)Math.Asin(rollComponents.X * rollComponents.X) * m_bankingEfficiency;
+ float yawAngle = m_angularMotorDirection.X * m_bankingEfficiency;
// actual error = static turn error + dynamic turn error
- float mixedYawAngle = yawAngle * (1f - m_bankingMix) + yawAngle * m_bankingMix * VehicleForwardSpeed;
-
- // TODO: the banking effect should not go to infinity but what to limit it to?
- mixedYawAngle = ClampInRange(-20f, mixedYawAngle, 20f);
+ float mixedYawAngle =(yawAngle * (1f - m_bankingMix)) + ((yawAngle * m_bankingMix) * VehicleForwardSpeed);
+ // TODO: the banking effect should not go to infinity but what to limit it to? and what should happen when this is
+ // being added to a user defined yaw that is already PI*4?
+ mixedYawAngle = ClampInRange(-12, mixedYawAngle, 12);
// Build the force vector to change rotation from what it is to what it should be
bankingContributionV.Z = -mixedYawAngle;
- // Don't do it all at once.
- bankingContributionV /= m_bankingTimescale;
+ // Don't do it all at once. 60 becouse 1 second is too fast with most user defined roll as PI*4
+ bankingContributionV /= m_bankingTimescale*60;
- VehicleRotationalVelocity += bankingContributionV * VehicleOrientation;
+ //VehicleRotationalVelocity += bankingContributionV * VehicleOrientation;
+ VehicleRotationalVelocity += bankingContributionV;
+
VDetailLog("{0}, MoveAngular,Banking,rollComp={1},speed={2},rollComp={3},yAng={4},mYAng={5},ret={6}",
Prim.LocalID, rollComponents, VehicleForwardSpeed, rollComponents, yawAngle, mixedYawAngle, bankingContributionV);
--
cgit v1.1
From 464201b41d5f5fdd7c88ab5e95dd7b6fbae6d766 Mon Sep 17 00:00:00 2001
From: Robert Adams
Date: Sat, 16 Mar 2013 15:34:07 -0700
Subject: BulletSim: add INI parameter for angular banking timescale fudge
parameter.
---
OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs | 12 ++++++------
OpenSim/Region/Physics/BulletSPlugin/BSParam.cs | 7 ++++++-
2 files changed, 12 insertions(+), 7 deletions(-)
(limited to 'OpenSim')
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
index 96eaa6b..38596fa 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
@@ -1437,21 +1437,21 @@ namespace OpenSim.Region.Physics.BulletSPlugin
// As the vehicle rolls to the right or left, the Y value will increase from
// zero (straight up) to 1 or -1 (full tilt right or left)
Vector3 rollComponents = Vector3.UnitZ * VehicleOrientation;
+
// Figure out the yaw value for this much roll.
- // Squared because that seems to give a good value
- // float yawAngle = (float)Math.Asin(rollComponents.X * rollComponents.X) * m_bankingEfficiency;
float yawAngle = m_angularMotorDirection.X * m_bankingEfficiency;
// actual error = static turn error + dynamic turn error
float mixedYawAngle =(yawAngle * (1f - m_bankingMix)) + ((yawAngle * m_bankingMix) * VehicleForwardSpeed);
- // TODO: the banking effect should not go to infinity but what to limit it to? and what should happen when this is
- // being added to a user defined yaw that is already PI*4?
+
+ // TODO: the banking effect should not go to infinity but what to limit it to?
+ // And what should happen when this is being added to a user defined yaw that is already PI*4?
mixedYawAngle = ClampInRange(-12, mixedYawAngle, 12);
// Build the force vector to change rotation from what it is to what it should be
bankingContributionV.Z = -mixedYawAngle;
- // Don't do it all at once. 60 becouse 1 second is too fast with most user defined roll as PI*4
- bankingContributionV /= m_bankingTimescale*60;
+ // Don't do it all at once. Fudge because 1 second is too fast with most user defined roll as PI*4.
+ bankingContributionV /= m_bankingTimescale * BSParam.VehicleAngularBankingTimescaleFudge;
//VehicleRotationalVelocity += bankingContributionV * VehicleOrientation;
VehicleRotationalVelocity += bankingContributionV;
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs b/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs
index 2af8468..77bdacb 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs
@@ -123,6 +123,7 @@ public static class BSParam
public static Vector3 VehicleLinearFactor { get; private set; }
public static Vector3 VehicleAngularFactor { get; private set; }
public static float VehicleGroundGravityFudge { get; private set; }
+ public static float VehicleAngularBankingTimescaleFudge { get; private set; }
public static bool VehicleDebuggingEnabled { get; private set; }
// Linkset implementation parameters
@@ -543,10 +544,14 @@ public static class BSParam
0.0f,
(s) => { return VehicleRestitution; },
(s,v) => { VehicleRestitution = v; } ),
- new ParameterDefn("VehicleGroundGravityFudge", "Factor to multiple gravity if a ground vehicle is probably on the ground (0.0 - 1.0)",
+ new ParameterDefn("VehicleGroundGravityFudge", "Factor to multiply gravity if a ground vehicle is probably on the ground (0.0 - 1.0)",
0.2f,
(s) => { return VehicleGroundGravityFudge; },
(s,v) => { VehicleGroundGravityFudge = v; } ),
+ new ParameterDefn("VehicleAngularBankingTimescaleFudge", "Factor to multiple angular banking timescale. Tune to increase realism.",
+ 60.0f,
+ (s) => { return VehicleAngularBankingTimescaleFudge; },
+ (s,v) => { VehicleAngularBankingTimescaleFudge = v; } ),
new ParameterDefn("VehicleDebuggingEnable", "Turn on/off vehicle debugging",
false,
(s) => { return VehicleDebuggingEnabled; },
--
cgit v1.1