diff --git a/OpenSim/ApplicationPlugins/Rest/Inventory/RequestData.cs b/OpenSim/ApplicationPlugins/Rest/Inventory/RequestData.cs
index 2ce5166630..9a8aef0af1 100644
--- a/OpenSim/ApplicationPlugins/Rest/Inventory/RequestData.cs
+++ b/OpenSim/ApplicationPlugins/Rest/Inventory/RequestData.cs
@@ -1272,8 +1272,9 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
if (buffer != null && buffer.Length != 0)
{
- Rest.Log.DebugFormat("{0} Entity buffer, length = {1} : <{2}>",
- MsgId, buffer.Length, encoding.GetString(buffer));
+ Rest.Log.DebugFormat("{0} Entity buffer, length = {1}", MsgId, buffer.Length);
+ // Rest.Log.DebugFormat("{0} Entity buffer, length = {1} : <{2}>",
+ // MsgId, buffer.Length, encoding.GetString(buffer));
response.OutputStream.Write(buffer, 0, buffer.Length);
}
diff --git a/OpenSim/ApplicationPlugins/Rest/Inventory/RestFileServices.cs b/OpenSim/ApplicationPlugins/Rest/Inventory/RestFileServices.cs
new file mode 100644
index 0000000000..0acef1d3a6
--- /dev/null
+++ b/OpenSim/ApplicationPlugins/Rest/Inventory/RestFileServices.cs
@@ -0,0 +1,447 @@
+/*
+ * Copyright (c) Contributors, http://opensimulator.org/
+ * See CONTRIBUTORS.TXT for a full list of copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the OpenSim Project nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+using System;
+using System.Xml;
+using System.IO;
+using OpenMetaverse;
+using OpenSim.Framework;
+using OpenSim.Framework.Servers;
+
+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
+
+ ///
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));
+
+ }
+
+ ///
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));
+
+ }
+
+ ///
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));
+
+ }
+
+ ///