Merge branch 'master' into careminster
						commit
						cef51cf91b
					
				|  | @ -1,43 +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 | ||||
| { | ||||
|     /// <summary> | ||||
|     /// This interface represents the boundary between the general purpose | ||||
|     /// REST plugin handling, and the functionally specific handlers. The | ||||
|     /// handler knows only to initialize and terminate all such handlers  | ||||
|     /// that it finds. Implementing this interface identifies the class as | ||||
|     /// a REST handler implementation. | ||||
|     /// </summary> | ||||
| 
 | ||||
|     internal interface IRest | ||||
|     { | ||||
|         void Initialize(); | ||||
|         void Close(); | ||||
|     } | ||||
| } | ||||
|  | @ -1,59 +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 OpenSim.Framework.Servers.HttpServer; | ||||
| 
 | ||||
| namespace OpenSim.ApplicationPlugins.Rest.Inventory | ||||
| { | ||||
| 
 | ||||
|     /// <remarks> | ||||
|     /// The handler delegates are not noteworthy. The allocator allows | ||||
|     /// a given handler to optionally subclass the base RequestData | ||||
|     /// structure to carry any locally required per-request state | ||||
|     /// needed. | ||||
|     /// </remarks> | ||||
| 
 | ||||
|     public delegate void        RestMethodHandler(RequestData rdata); | ||||
|     public delegate RequestData RestMethodAllocator(OSHttpRequest request, OSHttpResponse response, string path); | ||||
| 
 | ||||
|     /// <summary> | ||||
|     /// This interface exports the generic plugin-handling services | ||||
|     /// available to each loaded REST services module (IRest implementation) | ||||
|     /// </summary> | ||||
| 
 | ||||
|     internal interface IRestHandler | ||||
|     { | ||||
| 
 | ||||
|         string MsgId     { get; } | ||||
|         string RequestId { get; } | ||||
| 
 | ||||
|         void   AddPathHandler(RestMethodHandler mh, string path, RestMethodAllocator ma); | ||||
|         void AddStreamHandler(string httpMethod, string path, RestMethod method); | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
| } | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							|  | @ -1,11 +0,0 @@ | |||
| <Addin id="OpenSim.ApplicationPlugins.Rest.Inventory" version="0.1"> | ||||
|     <Runtime> | ||||
|         <Import assembly="OpenSim.ApplicationPlugins.Rest.Inventory.dll"/> | ||||
|     </Runtime> | ||||
|     <Dependencies> | ||||
|         <Addin id="OpenSim" version="0.5" /> | ||||
|     </Dependencies> | ||||
|     <Extension path = "/OpenSim/Startup"> | ||||
|         <Plugin id="RestInventory" type="OpenSim.ApplicationPlugins.Rest.Inventory.RestHandler" /> | ||||
|     </Extension> | ||||
| </Addin> | ||||
|  | @ -1,551 +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 System.Text; | ||||
| using log4net; | ||||
| using Nini.Config; | ||||
| using OpenSim.Framework; | ||||
| using OpenSim.Framework.Communications; | ||||
| using OpenSim.Services.Interfaces; | ||||
| using IAvatarService = OpenSim.Services.Interfaces.IAvatarService; | ||||
| 
 | ||||
| namespace OpenSim.ApplicationPlugins.Rest.Inventory | ||||
| { | ||||
|     public class Rest | ||||
|     { | ||||
|         internal static readonly ILog Log = | ||||
|             LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||||
| 
 | ||||
|         internal static bool DEBUG = Log.IsDebugEnabled; | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Supported authentication schemes | ||||
|         /// </summary> | ||||
| 
 | ||||
|         public const string AS_BASIC                      = "Basic";           // simple user/password verification | ||||
|         public const string AS_DIGEST                     = "Digest";          // password safe authentication | ||||
| 
 | ||||
|         /// Supported Digest algorithms | ||||
| 
 | ||||
|         public const string Digest_MD5                    = "MD5";             // assumed default if omitted | ||||
|         public const string Digest_MD5Sess                = "MD5-sess";        // session-span - not good for REST? | ||||
| 
 | ||||
|         public const string Qop_Auth                      = "auth";            // authentication only | ||||
|         public const string Qop_Int                       = "auth-int";        // TODO | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// These values have a single value for the whole | ||||
|         /// domain and lifetime of the plugin handler. We | ||||
|         /// make them static for ease of reference within | ||||
|         /// the assembly. These are initialized by the | ||||
|         /// RestHandler class during start-up. | ||||
|         /// </summary> | ||||
| 
 | ||||
|         internal static IRestHandler              Plugin            = null; | ||||
|         internal static OpenSimBase               main              = null; | ||||
|         internal static string                    Prefix            = null; | ||||
|         internal static IConfig                   Config            = null; | ||||
|         internal static string                    GodKey            = null; | ||||
|         internal static bool                      Authenticate      = true; | ||||
|         internal static bool                      Secure            = true; | ||||
|         internal static bool                      ExtendedEscape    = true; | ||||
|         internal static bool                      DumpAsset         = false; | ||||
|         internal static bool                      Fill              = true; | ||||
|         internal static bool                      FlushEnabled      = true; | ||||
|         internal static string                    Realm             = "OpenSim REST"; | ||||
|         internal static string                    Scheme            = AS_BASIC; | ||||
|         internal static int                       DumpLineSize      = 32; // Should be a multiple of 16 or (possibly) 4 | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// These are all dependent upon the Comms manager | ||||
|         /// being initialized. So they have to be properties | ||||
|         /// because the comms manager is now a module and is | ||||
|         /// not guaranteed to be there when the rest handler | ||||
|         /// initializes. | ||||
|         /// </summary> | ||||
| 
 | ||||
|         internal static IInventoryService InventoryServices | ||||
|         { | ||||
|             get { return main.SceneManager.CurrentOrFirstScene.InventoryService; } | ||||
|         } | ||||
| 
 | ||||
|         internal static IUserAccountService UserServices | ||||
|         { | ||||
|             get { return main.SceneManager.CurrentOrFirstScene.UserAccountService; } | ||||
|         } | ||||
| 
 | ||||
|         internal static IAuthenticationService AuthServices | ||||
|         { | ||||
|             get { return main.SceneManager.CurrentOrFirstScene.AuthenticationService; } | ||||
|         } | ||||
|          | ||||
|         internal static IAvatarService AvatarServices | ||||
|         { | ||||
|             get { return main.SceneManager.CurrentOrFirstScene.AvatarService; } | ||||
|         } | ||||
| 
 | ||||
|         internal static IAssetService AssetServices | ||||
|         { | ||||
|             get { return main.SceneManager.CurrentOrFirstScene.AssetService; } | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// HTTP requires that status information be generated for PUT | ||||
|         /// and POST opertaions. This is in support of that. The | ||||
|         /// operation verb gets substituted into the first string, | ||||
|         /// and the completion code is inserted into the tail. The | ||||
|         /// strings are put here to encourage consistency. | ||||
|         /// </summary> | ||||
| 
 | ||||
|         internal static string                    statusHead        = "<html><body><title>{0} status</title><break>"; | ||||
|         internal static string                    statusTail        = "</body></html>"; | ||||
| 
 | ||||
|         internal static Dictionary<int,string> HttpStatusDesc; | ||||
| 
 | ||||
|         static Rest() | ||||
|         { | ||||
|             HttpStatusDesc = new Dictionary<int,string>(); | ||||
|             if (HttpStatusCodeArray.Length != HttpStatusDescArray.Length) | ||||
|             { | ||||
|                 Log.ErrorFormat("{0} HTTP Status Code and Description arrays do not match"); | ||||
|                 throw new Exception("HTTP Status array discrepancy"); | ||||
|             } | ||||
| 
 | ||||
|             // Repackage the data into something more tractable. The sparse | ||||
|             // nature of HTTP return codes makes an array a bad choice. | ||||
| 
 | ||||
|             for (int i=0; i<HttpStatusCodeArray.Length; i++) | ||||
|             { | ||||
|                 HttpStatusDesc.Add(HttpStatusCodeArray[i], HttpStatusDescArray[i]); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         internal static int CreationDate | ||||
|         { | ||||
|             get { return (int) (DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalSeconds; } | ||||
|         } | ||||
| 
 | ||||
|         internal static string MsgId | ||||
|         { | ||||
|             get { return Plugin.MsgId; } | ||||
|         } | ||||
| 
 | ||||
|         internal static string RequestId | ||||
|         { | ||||
|             get { return Plugin.RequestId; } | ||||
|         } | ||||
| 
 | ||||
|         internal static Encoding Encoding = Util.UTF8; | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Version control for REST implementation. This | ||||
|         /// refers to the overall infrastructure represented | ||||
|         /// by the following classes | ||||
|         ///     RequestData | ||||
|         ///     RequestInventoryPlugin | ||||
|         ///     Rest | ||||
|         /// It does no describe implementation classes such as | ||||
|         /// RestInventoryServices, which may morph much more | ||||
|         /// often. Such classes ARE dependent upon this however | ||||
|         /// and should check it in their Initialize method. | ||||
|         /// </summary> | ||||
| 
 | ||||
|         public static readonly float Version  = 1.0F; | ||||
|         public const  string  Name            = "REST 1.0"; | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Currently defined HTTP methods. | ||||
|         /// Only GET and HEAD are required to be | ||||
|         /// supported by all servers. See Respond | ||||
|         /// to see how these are handled. | ||||
|         /// </summary> | ||||
| 
 | ||||
|         // REST AGENT 1.0 interpretations | ||||
|         public const string GET     = "get";       // information retrieval - server state unchanged | ||||
|         public const string HEAD    = "head";      // same as get except only the headers are returned. | ||||
|         public const string POST    = "post";      // Replace the URI designated resource with the entity. | ||||
|         public const string PUT     = "put";       // Add the entity to the context represented by the URI | ||||
|         public const string DELETE  = "delete";    // Remove the URI designated resource from the server. | ||||
| 
 | ||||
|         public const string OPTIONS = "options";  // | ||||
|         public const string TRACE   = "trace";    // | ||||
|         public const string CONNECT = "connect";  // | ||||
| 
 | ||||
|         // Define this in one place... | ||||
| 
 | ||||
|         public const string UrlPathSeparator   = "/"; | ||||
|         public const string UrlMethodSeparator = ":"; | ||||
| 
 | ||||
|         // Redirection qualifications | ||||
| 
 | ||||
|         public const bool PERMANENT = false; | ||||
|         public const bool TEMPORARY = true; | ||||
| 
 | ||||
|         // Constant arrays used by String.Split | ||||
| 
 | ||||
|         public   static   readonly char   C_SPACE    = ' '; | ||||
|         public   static   readonly char   C_SLASH    = '/'; | ||||
|         public   static   readonly char   C_PATHSEP  = '/'; | ||||
|         public   static   readonly char   C_COLON    = ':'; | ||||
|         public   static   readonly char   C_PLUS     = '+'; | ||||
|         public   static   readonly char   C_PERIOD   = '.'; | ||||
|         public   static   readonly char   C_COMMA    = ','; | ||||
|         public   static   readonly char   C_DQUOTE   = '"'; | ||||
| 
 | ||||
|         public   static   readonly string   CS_SPACE    = " "; | ||||
|         public   static   readonly string   CS_SLASH    = "/"; | ||||
|         public   static   readonly string   CS_PATHSEP  = "/"; | ||||
|         public   static   readonly string   CS_COLON    = ":"; | ||||
|         public   static   readonly string   CS_PLUS     = "+"; | ||||
|         public   static   readonly string   CS_PERIOD   = "."; | ||||
|         public   static   readonly string   CS_COMMA    = ","; | ||||
|         public   static   readonly string   CS_DQUOTE   = "\""; | ||||
| 
 | ||||
|         public   static   readonly char[] CA_SPACE   = { C_SPACE   }; | ||||
|         public   static   readonly char[] CA_SLASH   = { C_SLASH   }; | ||||
|         public   static   readonly char[] CA_PATHSEP = { C_PATHSEP }; | ||||
|         public   static   readonly char[] CA_COLON   = { C_COLON   }; | ||||
|         public   static   readonly char[] CA_PERIOD  = { C_PERIOD  }; | ||||
|         public   static   readonly char[] CA_PLUS    = { C_PLUS    }; | ||||
|         public   static   readonly char[] CA_COMMA   = { C_COMMA   }; | ||||
|         public   static   readonly char[] CA_DQUOTE  = { C_DQUOTE  }; | ||||
| 
 | ||||
|         // HTTP Code Values (in value order) | ||||
| 
 | ||||
|         public const int HttpStatusCodeContinue           = 100; | ||||
|         public const int HttpStatusCodeSwitchingProtocols = 101; | ||||
| 
 | ||||
|         public const int HttpStatusCodeOK                 = 200; | ||||
|         public const int HttpStatusCodeCreated            = 201; | ||||
|         public const int HttpStatusCodeAccepted           = 202; | ||||
|         public const int HttpStatusCodeNonAuthoritative   = 203; | ||||
|         public const int HttpStatusCodeNoContent          = 204; | ||||
|         public const int HttpStatusCodeResetContent       = 205; | ||||
|         public const int HttpStatusCodePartialContent     = 206; | ||||
| 
 | ||||
|         public const int HttpStatusCodeMultipleChoices    = 300; | ||||
|         public const int HttpStatusCodePermanentRedirect  = 301; | ||||
|         public const int HttpStatusCodeFound              = 302; | ||||
|         public const int HttpStatusCodeSeeOther           = 303; | ||||
|         public const int HttpStatusCodeNotModified        = 304; | ||||
|         public const int HttpStatusCodeUseProxy           = 305; | ||||
|         public const int HttpStatusCodeReserved306        = 306; | ||||
|         public const int HttpStatusCodeTemporaryRedirect  = 307; | ||||
| 
 | ||||
|         public const int HttpStatusCodeBadRequest         = 400; | ||||
|         public const int HttpStatusCodeNotAuthorized      = 401; | ||||
|         public const int HttpStatusCodePaymentRequired    = 402; | ||||
|         public const int HttpStatusCodeForbidden          = 403; | ||||
|         public const int HttpStatusCodeNotFound           = 404; | ||||
|         public const int HttpStatusCodeMethodNotAllowed   = 405; | ||||
|         public const int HttpStatusCodeNotAcceptable      = 406; | ||||
|         public const int HttpStatusCodeProxyAuthenticate  = 407; | ||||
|         public const int HttpStatusCodeTimeOut            = 408; | ||||
|         public const int HttpStatusCodeConflict           = 409; | ||||
|         public const int HttpStatusCodeGone               = 410; | ||||
|         public const int HttpStatusCodeLengthRequired     = 411; | ||||
|         public const int HttpStatusCodePreconditionFailed = 412; | ||||
|         public const int HttpStatusCodeEntityTooLarge     = 413; | ||||
|         public const int HttpStatusCodeUriTooLarge        = 414; | ||||
|         public const int HttpStatusCodeUnsupportedMedia   = 415; | ||||
|         public const int HttpStatusCodeRangeNotSatsified  = 416; | ||||
|         public const int HttpStatusCodeExpectationFailed  = 417; | ||||
| 
 | ||||
|         public const int HttpStatusCodeServerError        = 500; | ||||
|         public const int HttpStatusCodeNotImplemented     = 501; | ||||
|         public const int HttpStatusCodeBadGateway         = 502; | ||||
|         public const int HttpStatusCodeServiceUnavailable = 503; | ||||
|         public const int HttpStatusCodeGatewayTimeout     = 504; | ||||
|         public const int HttpStatusCodeHttpVersionError   = 505; | ||||
| 
 | ||||
|         public static readonly int[] HttpStatusCodeArray  = { | ||||
|             HttpStatusCodeContinue, | ||||
|             HttpStatusCodeSwitchingProtocols, | ||||
|             HttpStatusCodeOK, | ||||
|             HttpStatusCodeCreated, | ||||
|             HttpStatusCodeAccepted, | ||||
|             HttpStatusCodeNonAuthoritative, | ||||
|             HttpStatusCodeNoContent, | ||||
|             HttpStatusCodeResetContent, | ||||
|             HttpStatusCodePartialContent, | ||||
|             HttpStatusCodeMultipleChoices, | ||||
|             HttpStatusCodePermanentRedirect, | ||||
|             HttpStatusCodeFound, | ||||
|             HttpStatusCodeSeeOther, | ||||
|             HttpStatusCodeNotModified, | ||||
|             HttpStatusCodeUseProxy, | ||||
|             HttpStatusCodeReserved306, | ||||
|             HttpStatusCodeTemporaryRedirect, | ||||
|             HttpStatusCodeBadRequest, | ||||
|             HttpStatusCodeNotAuthorized, | ||||
|             HttpStatusCodePaymentRequired, | ||||
|             HttpStatusCodeForbidden, | ||||
|             HttpStatusCodeNotFound, | ||||
|             HttpStatusCodeMethodNotAllowed, | ||||
|             HttpStatusCodeNotAcceptable, | ||||
|             HttpStatusCodeProxyAuthenticate, | ||||
|             HttpStatusCodeTimeOut, | ||||
|             HttpStatusCodeConflict, | ||||
|             HttpStatusCodeGone, | ||||
|             HttpStatusCodeLengthRequired, | ||||
|             HttpStatusCodePreconditionFailed, | ||||
|             HttpStatusCodeEntityTooLarge, | ||||
|             HttpStatusCodeUriTooLarge, | ||||
|             HttpStatusCodeUnsupportedMedia, | ||||
|             HttpStatusCodeRangeNotSatsified, | ||||
|             HttpStatusCodeExpectationFailed, | ||||
|             HttpStatusCodeServerError, | ||||
|             HttpStatusCodeNotImplemented, | ||||
|             HttpStatusCodeBadGateway, | ||||
|             HttpStatusCodeServiceUnavailable, | ||||
|             HttpStatusCodeGatewayTimeout, | ||||
|             HttpStatusCodeHttpVersionError | ||||
|         }; | ||||
| 
 | ||||
|         // HTTP Status Descriptions (in status code order) | ||||
|         // This array must be kept strictly consistent with respect | ||||
|         // to the status code array above. | ||||
| 
 | ||||
|         public static readonly string[] HttpStatusDescArray  = { | ||||
|             "Continue Request", | ||||
|             "Switching Protocols", | ||||
|             "OK", | ||||
|             "CREATED", | ||||
|             "ACCEPTED", | ||||
|             "NON-AUTHORITATIVE INFORMATION", | ||||
|             "NO CONTENT", | ||||
|             "RESET CONTENT", | ||||
|             "PARTIAL CONTENT", | ||||
|             "MULTIPLE CHOICES", | ||||
|             "PERMANENT REDIRECT", | ||||
|             "FOUND", | ||||
|             "SEE OTHER", | ||||
|             "NOT MODIFIED", | ||||
|             "USE PROXY", | ||||
|             "RESERVED CODE 306", | ||||
|             "TEMPORARY REDIRECT", | ||||
|             "BAD REQUEST", | ||||
|             "NOT AUTHORIZED", | ||||
|             "PAYMENT REQUIRED", | ||||
|             "FORBIDDEN", | ||||
|             "NOT FOUND", | ||||
|             "METHOD NOT ALLOWED", | ||||
|             "NOT ACCEPTABLE", | ||||
|             "PROXY AUTHENTICATION REQUIRED", | ||||
|             "TIMEOUT", | ||||
|             "CONFLICT", | ||||
|             "GONE", | ||||
|             "LENGTH REQUIRED", | ||||
|             "PRECONDITION FAILED", | ||||
|             "ENTITY TOO LARGE", | ||||
|             "URI TOO LARGE", | ||||
|             "UNSUPPORTED MEDIA", | ||||
|             "RANGE NOT SATISFIED", | ||||
|             "EXPECTATION FAILED", | ||||
|             "SERVER ERROR", | ||||
|             "NOT IMPLEMENTED", | ||||
|             "BAD GATEWAY", | ||||
|             "SERVICE UNAVAILABLE", | ||||
|             "GATEWAY TIMEOUT", | ||||
|             "HTTP VERSION NOT SUPPORTED" | ||||
|         }; | ||||
| 
 | ||||
|         // HTTP Headers | ||||
| 
 | ||||
|         public const string HttpHeaderAccept              = "Accept"; | ||||
|         public const string HttpHeaderAcceptCharset       = "Accept-Charset"; | ||||
|         public const string HttpHeaderAcceptEncoding      = "Accept-Encoding"; | ||||
|         public const string HttpHeaderAcceptLanguage      = "Accept-Language"; | ||||
|         public const string HttpHeaderAcceptRanges        = "Accept-Ranges"; | ||||
|         public const string HttpHeaderAge                 = "Age"; | ||||
|         public const string HttpHeaderAllow               = "Allow"; | ||||
|         public const string HttpHeaderAuthorization       = "Authorization"; | ||||
|         public const string HttpHeaderCacheControl        = "Cache-Control"; | ||||
|         public const string HttpHeaderConnection          = "Connection"; | ||||
|         public const string HttpHeaderContentEncoding     = "Content-Encoding"; | ||||
|         public const string HttpHeaderContentLanguage     = "Content-Language"; | ||||
|         public const string HttpHeaderContentLength       = "Content-Length"; | ||||
|         public const string HttpHeaderContentLocation     = "Content-Location"; | ||||
|         public const string HttpHeaderContentMD5          = "Content-MD5"; | ||||
|         public const string HttpHeaderContentRange        = "Content-Range"; | ||||
|         public const string HttpHeaderContentType         = "Content-Type"; | ||||
|         public const string HttpHeaderDate                = "Date"; | ||||
|         public const string HttpHeaderETag                = "ETag"; | ||||
|         public const string HttpHeaderExpect              = "Expect"; | ||||
|         public const string HttpHeaderExpires             = "Expires"; | ||||
|         public const string HttpHeaderFrom                = "From"; | ||||
|         public const string HttpHeaderHost                = "Host"; | ||||
|         public const string HttpHeaderIfMatch             = "If-Match"; | ||||
|         public const string HttpHeaderIfModifiedSince     = "If-Modified-Since"; | ||||
|         public const string HttpHeaderIfNoneMatch         = "If-None-Match"; | ||||
|         public const string HttpHeaderIfRange             = "If-Range"; | ||||
|         public const string HttpHeaderIfUnmodifiedSince   = "If-Unmodified-Since"; | ||||
|         public const string HttpHeaderLastModified        = "Last-Modified"; | ||||
|         public const string HttpHeaderLocation            = "Location"; | ||||
|         public const string HttpHeaderMaxForwards         = "Max-Forwards"; | ||||
|         public const string HttpHeaderPragma              = "Pragma"; | ||||
|         public const string HttpHeaderProxyAuthenticate   = "Proxy-Authenticate"; | ||||
|         public const string HttpHeaderProxyAuthorization  = "Proxy-Authorization"; | ||||
|         public const string HttpHeaderRange               = "Range"; | ||||
|         public const string HttpHeaderReferer             = "Referer"; | ||||
|         public const string HttpHeaderRetryAfter          = "Retry-After"; | ||||
|         public const string HttpHeaderServer              = "Server"; | ||||
|         public const string HttpHeaderTE                  = "TE"; | ||||
|         public const string HttpHeaderTrailer             = "Trailer"; | ||||
|         public const string HttpHeaderTransferEncoding    = "Transfer-Encoding"; | ||||
|         public const string HttpHeaderUpgrade             = "Upgrade"; | ||||
|         public const string HttpHeaderUserAgent           = "User-Agent"; | ||||
|         public const string HttpHeaderVary                = "Vary"; | ||||
|         public const string HttpHeaderVia                 = "Via"; | ||||
|         public const string HttpHeaderWarning             = "Warning"; | ||||
|         public const string HttpHeaderWWWAuthenticate     = "WWW-Authenticate"; | ||||
| 
 | ||||
|         /// Utility routines | ||||
| 
 | ||||
|         public static string StringToBase64(string str) | ||||
|         { | ||||
|             try | ||||
|             { | ||||
|                 byte[] encData_byte = new byte[str.Length]; | ||||
|                 encData_byte = Util.UTF8.GetBytes(str); | ||||
|                 return Convert.ToBase64String(encData_byte); | ||||
|             } | ||||
|             catch | ||||
|             { | ||||
|                 return String.Empty; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         public static string Base64ToString(string str) | ||||
|         { | ||||
|             try | ||||
|             { | ||||
|                 return Util.Base64ToString(str); | ||||
|             } | ||||
|             catch | ||||
|             { | ||||
|                 return String.Empty; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         private const string hvals = "0123456789abcdef"; | ||||
| 
 | ||||
|         public static int Hex2Int(string hex) | ||||
|         { | ||||
|             int    val = 0; | ||||
|             int    sum = 0; | ||||
|             string tmp = null; | ||||
| 
 | ||||
|             if (hex != null) | ||||
|             { | ||||
|                 tmp = hex.ToLower(); | ||||
|                 for (int i = 0; i < tmp.Length; i++) | ||||
|                 { | ||||
|                     val = hvals.IndexOf(tmp[i]); | ||||
|                     if (val == -1) | ||||
|                         break; | ||||
|                     sum *= 16; | ||||
|                     sum += val; | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             return sum; | ||||
|         } | ||||
| 
 | ||||
|         // Nonce management | ||||
| 
 | ||||
|         public static string NonceGenerator() | ||||
|         { | ||||
|             return StringToBase64(CreationDate + Guid.NewGuid().ToString()); | ||||
|         } | ||||
| 
 | ||||
|         // Dump the specified data stream | ||||
| 
 | ||||
|         public static void Dump(byte[] data) | ||||
|         { | ||||
|             char[] buffer = new char[DumpLineSize]; | ||||
|             int cc = 0; | ||||
| 
 | ||||
|             for (int i = 0; i < data.Length; i++) | ||||
|             { | ||||
|                 if (i % DumpLineSize == 0) Console.Write("\n{0}: ",i.ToString("d8")); | ||||
| 
 | ||||
|                 if (i % 4  == 0) Console.Write(" "); | ||||
| 
 | ||||
|                 Console.Write("{0}",data[i].ToString("x2")); | ||||
| 
 | ||||
|                 if (data[i] < 127 && data[i] > 31) | ||||
|                     buffer[i % DumpLineSize] = (char) data[i]; | ||||
|                 else | ||||
|                     buffer[i % DumpLineSize] = '.'; | ||||
| 
 | ||||
|                 cc++; | ||||
| 
 | ||||
|                 if (i != 0 && (i + 1) % DumpLineSize == 0) | ||||
|                 { | ||||
|                     Console.Write(" |"+(new String(buffer))+"|"); | ||||
|                     cc = 0; | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             // Finish off any incomplete line | ||||
| 
 | ||||
|             if (cc != 0) | ||||
|             { | ||||
|                 for (int i = cc ; i < DumpLineSize; i++) | ||||
|                 { | ||||
|                     if (i % 4  == 0) Console.Write(" "); | ||||
|                     Console.Write("  "); | ||||
|                     buffer[i % DumpLineSize] = ' '; | ||||
|                 } | ||||
|                 Console.WriteLine(" |"+(new String(buffer))+"|"); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 Console.Write("\n"); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     // Local exception type | ||||
| 
 | ||||
|     public class RestException : Exception | ||||
|     { | ||||
|         internal int    statusCode; | ||||
|         internal string statusDesc; | ||||
|         internal string httpmethod; | ||||
|         internal string httppath; | ||||
| 
 | ||||
|         public RestException(string msg) : base(msg) | ||||
|         { | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | @ -1,860 +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; | ||||
| using System.Collections.Generic; | ||||
| using System.Xml; | ||||
| using OpenMetaverse; | ||||
| using OpenSim.Framework; | ||||
| using OpenSim.Framework.Servers; | ||||
| using OpenSim.Framework.Servers.HttpServer; | ||||
| using OpenSim.Services.Interfaces; | ||||
| 
 | ||||
| namespace OpenSim.ApplicationPlugins.Rest.Inventory | ||||
| { | ||||
| 
 | ||||
|     public class RestAppearanceServices : IRest | ||||
|     { | ||||
| //        private static readonly int PARM_USERID = 0; | ||||
| 
 | ||||
|         // private static readonly int PARM_PATH   = 1; | ||||
| 
 | ||||
| //        private bool       enabled = false; | ||||
|         private string     qPrefix = "appearance"; | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// The constructor makes sure that the service prefix is absolute | ||||
|         /// and the registers the service handler and the allocator. | ||||
|         /// </summary> | ||||
| 
 | ||||
|         public RestAppearanceServices() | ||||
|         { | ||||
|             Rest.Log.InfoFormat("{0} User appearance 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); | ||||
|                 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(DoAppearance,qPrefix,Allocate); | ||||
| 
 | ||||
|             // Activate if everything went OK | ||||
| 
 | ||||
| //            enabled = true; | ||||
| 
 | ||||
|             Rest.Log.InfoFormat("{0} User appearance services initialization complete", MsgId); | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Post-construction, pre-enabled initialization opportunity | ||||
|         /// Not currently exploited. | ||||
|         /// </summary> | ||||
| 
 | ||||
|         public void Initialize() | ||||
|         { | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Called by the plug-in to halt service processing. Local processing is | ||||
|         /// disabled. | ||||
|         /// </summary> | ||||
| 
 | ||||
|         public void Close() | ||||
|         { | ||||
| //            enabled = false; | ||||
|             Rest.Log.InfoFormat("{0} User appearance services closing down", MsgId); | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// This property is declared locally because it is used a lot and | ||||
|         /// brevity is nice. | ||||
|         /// </summary> | ||||
| 
 | ||||
|         internal string MsgId | ||||
|         { | ||||
|             get { return Rest.MsgId; } | ||||
|         } | ||||
| 
 | ||||
|         #region Interface | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// 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. | ||||
|         /// </summary> | ||||
|         /// <param name=request>Inbound HTTP request information</param> | ||||
|         /// <param name=response>Outbound HTTP request information</param> | ||||
|         /// <param name=qPrefix>REST service domain prefix</param> | ||||
|         /// <returns>A RequestData instance suitable for this service</returns> | ||||
| 
 | ||||
|         private RequestData Allocate(OSHttpRequest request, OSHttpResponse response, string prefix) | ||||
|         { | ||||
|             return (RequestData) new AppearanceRequestData(request, response, prefix); | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// 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 | ||||
|         /// </summary> | ||||
|         /// <param name=hdata>A consolidated HTTP request work area</param> | ||||
| 
 | ||||
|         private void DoAppearance(RequestData hdata) | ||||
|         { | ||||
|             // !!! REFACTORIMG PROBLEM. This needs rewriting for 0.7 | ||||
| 
 | ||||
|             //AppearanceRequestData rdata = (AppearanceRequestData) hdata; | ||||
| 
 | ||||
|             //Rest.Log.DebugFormat("{0} DoAppearance ENTRY", MsgId); | ||||
| 
 | ||||
|             //// 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://<host>:<port>/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} Appearance: 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} User profile obtained for agent {1} {2}", | ||||
|             //                         MsgId, rdata.userProfile.FirstName, rdata.userProfile.SurName); | ||||
|             //} | ||||
|             //else | ||||
|             //{ | ||||
|             //    Rest.Log.WarnFormat("{0} No user 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 | ||||
| 
 | ||||
|             //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 | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// This method implements GET processing for user's appearance. | ||||
|         /// </summary> | ||||
|         /// <param name=rdata>HTTP service request work area</param> | ||||
| 
 | ||||
| //        private void DoGet(AppearanceRequestData rdata) | ||||
| //        { | ||||
| //            AvatarData adata = Rest.AvatarServices.GetAvatar(rdata.userProfile.ID); | ||||
| // | ||||
| //            if (adata == null) | ||||
| //            { | ||||
| //                rdata.Fail(Rest.HttpStatusCodeNoContent, | ||||
| //                    String.Format("appearance data not found for user {0} {1}",  | ||||
| //                      rdata.userProfile.FirstName, rdata.userProfile.SurName)); | ||||
| //            } | ||||
| //            rdata.userAppearance = adata.ToAvatarAppearance(rdata.userProfile.ID); | ||||
| // | ||||
| //            rdata.initXmlWriter(); | ||||
| // | ||||
| //            FormatUserAppearance(rdata); | ||||
| // | ||||
| //            // 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("Appearance {0} Normal completion", rdata.method)); | ||||
| //        } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// POST adds NEW information to the user profile database. | ||||
|         /// This effectively resets the appearance before applying those | ||||
|         /// characteristics supplied in the request. | ||||
|         /// </summary> | ||||
| 
 | ||||
| //        private void DoExtend(AppearanceRequestData rdata) | ||||
| //        { | ||||
| // | ||||
| //            bool  created  = false; | ||||
| //            bool  modified = false; | ||||
| //            string newnode = String.Empty; | ||||
| // | ||||
| //            Rest.Log.DebugFormat("{0} POST ENTRY", MsgId); | ||||
| // | ||||
| //            //AvatarAppearance old = Rest.AvatarServices.GetUserAppearance(rdata.userProfile.ID); | ||||
| // | ||||
| //            rdata.userAppearance = new AvatarAppearance(); | ||||
| // | ||||
| //            //  Although the following behavior is admitted by HTTP I am becoming  | ||||
| //            //  increasingly doubtful that it is appropriate for REST. If I attempt to | ||||
| //            //  add a new record, and it already exists, then it seems to me that the | ||||
| //            //  attempt should fail, rather than update the existing record. | ||||
| //            AvatarData adata = null; | ||||
| //            if (GetUserAppearance(rdata)) | ||||
| //            { | ||||
| //                modified = rdata.userAppearance != null; | ||||
| //                created  = !modified; | ||||
| //                adata = new AvatarData(rdata.userAppearance); | ||||
| //                Rest.AvatarServices.SetAvatar(rdata.userProfile.ID, adata); | ||||
| //            //    Rest.UserServices.UpdateUserProfile(rdata.userProfile); | ||||
| //            } | ||||
| //            else | ||||
| //            { | ||||
| //                created  = true; | ||||
| //                adata = new AvatarData(rdata.userAppearance); | ||||
| //                Rest.AvatarServices.SetAvatar(rdata.userProfile.ID, adata); | ||||
| //             //   Rest.UserServices.UpdateUserProfile(rdata.userProfile); | ||||
| //            } | ||||
| // | ||||
| //            if (created) | ||||
| //            { | ||||
| //                newnode = String.Format("{0} {1}", rdata.userProfile.FirstName, | ||||
| //                                   rdata.userProfile.SurName); | ||||
| //                // Must include a location header with a URI that identifies the new resource. | ||||
| // | ||||
| //                rdata.AddHeader(Rest.HttpHeaderLocation,String.Format("http://{0}{1}:{2}{3}{4}", | ||||
| //                         rdata.hostname,rdata.port,rdata.path,Rest.UrlPathSeparator, newnode)); | ||||
| //                rdata.Complete(Rest.HttpStatusCodeCreated); | ||||
| // | ||||
| //            } | ||||
| //            else | ||||
| //            { | ||||
| //                if (modified) | ||||
| //                { | ||||
| //                    rdata.Complete(Rest.HttpStatusCodeOK); | ||||
| //                } | ||||
| //                else | ||||
| //                { | ||||
| //                    rdata.Complete(Rest.HttpStatusCodeNoContent); | ||||
| //                } | ||||
| //            } | ||||
| // | ||||
| //            rdata.Respond(String.Format("Appearance {0} : Normal completion", rdata.method)); | ||||
| // | ||||
| //        } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// This updates the user's appearance. not all aspects need to be provided, | ||||
|         /// only those supplied will be changed. | ||||
|         /// </summary> | ||||
| 
 | ||||
| //        private void DoUpdate(AppearanceRequestData rdata) | ||||
| //        { | ||||
| // | ||||
| //            // REFACTORING PROBLEM This was commented out. It doesn't work for 0.7 | ||||
| // | ||||
| //            //bool  created  = false; | ||||
| //            //bool  modified = false; | ||||
| // | ||||
| // | ||||
| //            //rdata.userAppearance = Rest.AvatarServices.GetUserAppearance(rdata.userProfile.ID); | ||||
| // | ||||
| //            //// If the user exists then this is considered a modification regardless | ||||
| //            //// of what may, or may not be, specified in the payload. | ||||
| // | ||||
| //            //if (rdata.userAppearance != null) | ||||
| //            //{ | ||||
| //            //    modified = true; | ||||
| //            //    Rest.AvatarServices.UpdateUserAppearance(rdata.userProfile.ID, rdata.userAppearance); | ||||
| //            //    Rest.UserServices.UpdateUserProfile(rdata.userProfile); | ||||
| //            //} | ||||
| // | ||||
| //            //if (created) | ||||
| //            //{ | ||||
| //            //    rdata.Complete(Rest.HttpStatusCodeCreated); | ||||
| //            //} | ||||
| //            //else | ||||
| //            //{ | ||||
| //            //    if (modified) | ||||
| //            //    { | ||||
| //            //        rdata.Complete(Rest.HttpStatusCodeOK); | ||||
| //            //    } | ||||
| //            //    else | ||||
| //            //    { | ||||
| //            //        rdata.Complete(Rest.HttpStatusCodeNoContent); | ||||
| //            //    } | ||||
| //            //} | ||||
| // | ||||
| //            rdata.Respond(String.Format("Appearance {0} : Normal completion", rdata.method)); | ||||
| // | ||||
| //        } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Delete the specified user's appearance. This actually performs a reset | ||||
|         /// to the default avatar appearance, if the info is already there.  | ||||
|         /// Existing ownership is preserved. All prior updates are lost and can not | ||||
|         /// be recovered. | ||||
|         /// </summary> | ||||
| //        private void DoDelete(AppearanceRequestData rdata) | ||||
| //        { | ||||
| //            AvatarData adata = Rest.AvatarServices.GetAvatar(rdata.userProfile.ID); | ||||
| // | ||||
| //            if (adata != null) | ||||
| //            { | ||||
| //                AvatarAppearance old = adata.ToAvatarAppearance(rdata.userProfile.ID); | ||||
| //                rdata.userAppearance = new AvatarAppearance(); | ||||
| //                rdata.userAppearance.Owner = old.Owner; | ||||
| //                adata = new AvatarData(rdata.userAppearance); | ||||
| // | ||||
| //                Rest.AvatarServices.SetAvatar(rdata.userProfile.ID, adata); | ||||
| // | ||||
| //                rdata.Complete(); | ||||
| //            } | ||||
| //            else | ||||
| //            { | ||||
| // | ||||
| //                rdata.Complete(Rest.HttpStatusCodeNoContent); | ||||
| //            } | ||||
| // | ||||
| //            rdata.Respond(String.Format("Appearance {0} : Normal completion", rdata.method)); | ||||
| //        } | ||||
| 
 | ||||
| #endregion method-specific processing | ||||
| 
 | ||||
|         private bool GetUserAppearance(AppearanceRequestData rdata) | ||||
|         { | ||||
| 
 | ||||
|             XmlReader xml; | ||||
|             bool indata = false; | ||||
| 
 | ||||
|             rdata.initXmlReader(); | ||||
|             xml     = rdata.reader; | ||||
| 
 | ||||
|             while (xml.Read()) | ||||
|             { | ||||
|                 switch (xml.NodeType) | ||||
|                 { | ||||
|                     case XmlNodeType.Element : | ||||
|                         switch (xml.Name) | ||||
|                         { | ||||
|                             case "Appearance" : | ||||
|                                 if (xml.MoveToAttribute("Height")) | ||||
|                                 { | ||||
|                                     rdata.userAppearance.AvatarHeight = (float) Convert.ToDouble(xml.Value); | ||||
|                                     indata = true; | ||||
|                                 } | ||||
| //                                if (xml.MoveToAttribute("Owner")) | ||||
| //                                { | ||||
| //                                    rdata.userAppearance.Owner = (UUID)xml.Value; | ||||
| //                                    indata = true; | ||||
| //                                } | ||||
|                                 if (xml.MoveToAttribute("Serial")) | ||||
|                                 { | ||||
|                                     rdata.userAppearance.Serial = Convert.ToInt32(xml.Value); | ||||
|                                     indata = true; | ||||
|                                 } | ||||
|                             break; | ||||
| /* | ||||
|                             case "Body" : | ||||
|                                 if (xml.MoveToAttribute("Item")) | ||||
|                                 { | ||||
|                                     rdata.userAppearance.BodyItem = (UUID)xml.Value; | ||||
|                                     indata = true; | ||||
|                                 } | ||||
|                                 if (xml.MoveToAttribute("Asset")) | ||||
|                                 { | ||||
|                                     rdata.userAppearance.BodyAsset = (UUID)xml.Value; | ||||
|                                     indata = true; | ||||
|                                 } | ||||
|                             break; | ||||
|                             case "Skin" : | ||||
|                                 if (xml.MoveToAttribute("Item")) | ||||
|                                 { | ||||
|                                     rdata.userAppearance.SkinItem = (UUID)xml.Value; | ||||
|                                     indata = true; | ||||
|                                 } | ||||
|                                 if (xml.MoveToAttribute("Asset")) | ||||
|                                 { | ||||
|                                     rdata.userAppearance.SkinAsset = (UUID)xml.Value; | ||||
|                                     indata = true; | ||||
|                                 } | ||||
|                             break; | ||||
|                             case "Hair" : | ||||
|                                 if (xml.MoveToAttribute("Item")) | ||||
|                                 { | ||||
|                                     rdata.userAppearance.HairItem = (UUID)xml.Value; | ||||
|                                     indata = true; | ||||
|                                 } | ||||
|                                 if (xml.MoveToAttribute("Asset")) | ||||
|                                 { | ||||
|                                     rdata.userAppearance.HairAsset = (UUID)xml.Value; | ||||
|                                     indata = true; | ||||
|                                 } | ||||
|                             break; | ||||
|                             case "Eyes" : | ||||
|                                 if (xml.MoveToAttribute("Item")) | ||||
|                                 { | ||||
|                                     rdata.userAppearance.EyesItem = (UUID)xml.Value; | ||||
|                                     indata = true; | ||||
|                                 } | ||||
|                                 if (xml.MoveToAttribute("Asset")) | ||||
|                                 { | ||||
|                                     rdata.userAppearance.EyesAsset = (UUID)xml.Value; | ||||
|                                     indata = true; | ||||
|                                 } | ||||
|                             break; | ||||
|                             case "Shirt" : | ||||
|                                 if (xml.MoveToAttribute("Item")) | ||||
|                                 { | ||||
|                                     rdata.userAppearance.ShirtItem = (UUID)xml.Value; | ||||
|                                     indata = true; | ||||
|                                 } | ||||
|                                 if (xml.MoveToAttribute("Asset")) | ||||
|                                 { | ||||
|                                     rdata.userAppearance.ShirtAsset = (UUID)xml.Value; | ||||
|                                     indata = true; | ||||
|                                 } | ||||
|                             break; | ||||
|                             case "Pants" : | ||||
|                                 if (xml.MoveToAttribute("Item")) | ||||
|                                 { | ||||
|                                     rdata.userAppearance.PantsItem = (UUID)xml.Value; | ||||
|                                     indata = true; | ||||
|                                 } | ||||
|                                 if (xml.MoveToAttribute("Asset")) | ||||
|                                 { | ||||
|                                     rdata.userAppearance.PantsAsset = (UUID)xml.Value; | ||||
|                                     indata = true; | ||||
|                                 } | ||||
|                             break; | ||||
|                             case "Shoes" : | ||||
|                                 if (xml.MoveToAttribute("Item")) | ||||
|                                 { | ||||
|                                     rdata.userAppearance.ShoesItem = (UUID)xml.Value; | ||||
|                                     indata = true; | ||||
|                                 } | ||||
|                                 if (xml.MoveToAttribute("Asset")) | ||||
|                                 { | ||||
|                                     rdata.userAppearance.ShoesAsset = (UUID)xml.Value; | ||||
|                                     indata = true; | ||||
|                                 } | ||||
|                             break; | ||||
|                             case "Socks" : | ||||
|                                 if (xml.MoveToAttribute("Item")) | ||||
|                                 { | ||||
|                                     rdata.userAppearance.SocksItem = (UUID)xml.Value; | ||||
|                                     indata = true; | ||||
|                                 } | ||||
|                                 if (xml.MoveToAttribute("Asset")) | ||||
|                                 { | ||||
|                                     rdata.userAppearance.SocksAsset = (UUID)xml.Value; | ||||
|                                     indata = true; | ||||
|                                 } | ||||
|                             break; | ||||
|                             case "Jacket" : | ||||
|                                 if (xml.MoveToAttribute("Item")) | ||||
|                                 { | ||||
|                                     rdata.userAppearance.JacketItem = (UUID)xml.Value; | ||||
|                                     indata = true; | ||||
|                                 } | ||||
|                                 if (xml.MoveToAttribute("Asset")) | ||||
|                                 { | ||||
|                                     rdata.userAppearance.JacketAsset = (UUID)xml.Value; | ||||
|                                     indata = true; | ||||
|                                 } | ||||
|                             break; | ||||
|                             case "Gloves" : | ||||
|                                 if (xml.MoveToAttribute("Item")) | ||||
|                                 { | ||||
|                                     rdata.userAppearance.GlovesItem = (UUID)xml.Value; | ||||
|                                     indata = true; | ||||
|                                 } | ||||
|                                 if (xml.MoveToAttribute("Asset")) | ||||
|                                 { | ||||
|                                     rdata.userAppearance.GlovesAsset = (UUID)xml.Value; | ||||
|                                     indata = true; | ||||
|                                 } | ||||
|                             break; | ||||
|                             case "UnderShirt" : | ||||
|                                 if (xml.MoveToAttribute("Item")) | ||||
|                                 { | ||||
|                                     rdata.userAppearance.UnderShirtItem = (UUID)xml.Value; | ||||
|                                     indata = true; | ||||
|                                 } | ||||
|                                 if (xml.MoveToAttribute("Asset")) | ||||
|                                 { | ||||
|                                     rdata.userAppearance.UnderShirtAsset = (UUID)xml.Value; | ||||
|                                     indata = true; | ||||
|                                 } | ||||
|                             break; | ||||
|                             case "UnderPants" : | ||||
|                                 if (xml.MoveToAttribute("Item")) | ||||
|                                 { | ||||
|                                     rdata.userAppearance.UnderPantsItem = (UUID)xml.Value; | ||||
|                                     indata = true; | ||||
|                                 } | ||||
|                                 if (xml.MoveToAttribute("Asset")) | ||||
|                                 { | ||||
|                                     rdata.userAppearance.UnderPantsAsset = (UUID)xml.Value; | ||||
|                                     indata = true; | ||||
|                                 } | ||||
|                             break; | ||||
|                             case "Skirt" : | ||||
|                                 if (xml.MoveToAttribute("Item")) | ||||
|                                 { | ||||
|                                     rdata.userAppearance.SkirtItem = (UUID)xml.Value; | ||||
|                                     indata = true; | ||||
|                                 } | ||||
|                                 if (xml.MoveToAttribute("Asset")) | ||||
|                                 { | ||||
|                                     rdata.userAppearance.SkirtAsset = (UUID)xml.Value; | ||||
|                                     indata = true; | ||||
|                                 } | ||||
|                             break; | ||||
| */ | ||||
|                             case "Attachment" : | ||||
|                                 { | ||||
| 
 | ||||
|                                     int  ap; | ||||
|                                     UUID asset; | ||||
|                                     UUID item; | ||||
| 
 | ||||
|                                     if (xml.MoveToAttribute("AtPoint")) | ||||
|                                     { | ||||
|                                         ap = Convert.ToInt32(xml.Value); | ||||
|                                         if (xml.MoveToAttribute("Asset")) | ||||
|                                         { | ||||
|                                             asset = new UUID(xml.Value); | ||||
|                                             if (xml.MoveToAttribute("Asset")) | ||||
|                                             { | ||||
|                                                 item = new UUID(xml.Value); | ||||
|                                                 rdata.userAppearance.SetAttachment(ap, item, asset); | ||||
|                                                 indata = true; | ||||
|                                             } | ||||
|                                         } | ||||
|                                     } | ||||
|                                 } | ||||
|                             break; | ||||
|                             case "Texture" : | ||||
|                                 if (xml.MoveToAttribute("Default")) | ||||
|                                 { | ||||
|                                     rdata.userAppearance.Texture = new Primitive.TextureEntry(new UUID(xml.Value)); | ||||
|                                     indata = true; | ||||
|                                 } | ||||
|                             break; | ||||
|                             case "Face" : | ||||
|                                 { | ||||
|                                     uint index; | ||||
|                                     if (xml.MoveToAttribute("Index")) | ||||
|                                     { | ||||
|                                         index = Convert.ToUInt32(xml.Value); | ||||
|                                         if (xml.MoveToAttribute("Id")) | ||||
|                                         { | ||||
|                                             rdata.userAppearance.Texture.CreateFace(index).TextureID = new UUID(xml.Value); | ||||
|                                             indata = true; | ||||
|                                         } | ||||
|                                     } | ||||
|                                 } | ||||
|                             break; | ||||
|                             case "VisualParameters" : | ||||
|                                 { | ||||
|                                     xml.ReadContentAsBase64(rdata.userAppearance.VisualParams, | ||||
|                                                             0, rdata.userAppearance.VisualParams.Length); | ||||
|                                     indata = true; | ||||
|                                 } | ||||
|                             break; | ||||
|                         }  | ||||
|                     break; | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             return indata; | ||||
| 
 | ||||
|         } | ||||
| 
 | ||||
|         private void FormatPart(AppearanceRequestData rdata, string part, UUID item, UUID asset) | ||||
|         { | ||||
|             if (item != UUID.Zero || asset != UUID.Zero) | ||||
|             { | ||||
|                 rdata.writer.WriteStartElement(part); | ||||
|                 if (item  != UUID.Zero) | ||||
|                 { | ||||
|                     rdata.writer.WriteAttributeString("Item",item.ToString()); | ||||
|                 } | ||||
| 
 | ||||
|                 if (asset != UUID.Zero) | ||||
|                 { | ||||
|                     rdata.writer.WriteAttributeString("Asset",asset.ToString()); | ||||
|                 } | ||||
|                 rdata.writer.WriteEndElement(); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         private void FormatUserAppearance(AppearanceRequestData rdata) | ||||
|         { | ||||
| 
 | ||||
|             Rest.Log.DebugFormat("{0} FormatUserAppearance", MsgId); | ||||
| 
 | ||||
|             if (rdata.userAppearance != null) | ||||
|             { | ||||
| 
 | ||||
|                 Rest.Log.DebugFormat("{0} FormatUserAppearance: appearance object exists", MsgId); | ||||
|                 rdata.writer.WriteStartElement("Appearance"); | ||||
| 
 | ||||
|                 rdata.writer.WriteAttributeString("Height", rdata.userAppearance.AvatarHeight.ToString()); | ||||
| //                if (rdata.userAppearance.Owner != UUID.Zero) | ||||
| //                    rdata.writer.WriteAttributeString("Owner", rdata.userAppearance.Owner.ToString()); | ||||
|                 rdata.writer.WriteAttributeString("Serial", rdata.userAppearance.Serial.ToString()); | ||||
| 
 | ||||
| /* | ||||
|                 FormatPart(rdata, "Body", rdata.userAppearance.BodyItem, rdata.userAppearance.BodyAsset); | ||||
|                 FormatPart(rdata, "Skin", rdata.userAppearance.SkinItem, rdata.userAppearance.SkinAsset); | ||||
|                 FormatPart(rdata, "Hair", rdata.userAppearance.HairItem, rdata.userAppearance.HairAsset); | ||||
|                 FormatPart(rdata, "Eyes", rdata.userAppearance.EyesItem, rdata.userAppearance.EyesAsset); | ||||
| 
 | ||||
|                 FormatPart(rdata, "Shirt", rdata.userAppearance.ShirtItem, rdata.userAppearance.ShirtAsset); | ||||
|                 FormatPart(rdata, "Pants", rdata.userAppearance.PantsItem, rdata.userAppearance.PantsAsset); | ||||
|                 FormatPart(rdata, "Skirt", rdata.userAppearance.SkirtItem, rdata.userAppearance.SkirtAsset); | ||||
|                 FormatPart(rdata, "Shoes", rdata.userAppearance.ShoesItem, rdata.userAppearance.ShoesAsset); | ||||
|                 FormatPart(rdata, "Socks", rdata.userAppearance.SocksItem, rdata.userAppearance.SocksAsset); | ||||
| 
 | ||||
|                 FormatPart(rdata, "Jacket", rdata.userAppearance.JacketItem, rdata.userAppearance.JacketAsset); | ||||
|                 FormatPart(rdata, "Gloves", rdata.userAppearance.GlovesItem, rdata.userAppearance.GlovesAsset); | ||||
| 
 | ||||
|                 FormatPart(rdata, "UnderShirt", rdata.userAppearance.UnderShirtItem, rdata.userAppearance.UnderShirtAsset); | ||||
|                 FormatPart(rdata, "UnderPants", rdata.userAppearance.UnderPantsItem, rdata.userAppearance.UnderPantsAsset); | ||||
| */ | ||||
|                 Rest.Log.DebugFormat("{0} FormatUserAppearance: Formatting attachments", MsgId); | ||||
| 
 | ||||
|                 rdata.writer.WriteStartElement("Attachments"); | ||||
|                 List<AvatarAttachment> attachments = rdata.userAppearance.GetAttachments(); | ||||
|                 foreach (AvatarAttachment attach in attachments) | ||||
|                 { | ||||
|                     rdata.writer.WriteStartElement("Attachment"); | ||||
|                     rdata.writer.WriteAttributeString("AtPoint", attach.AttachPoint.ToString()); | ||||
|                     rdata.writer.WriteAttributeString("Item", attach.ItemID.ToString()); | ||||
|                     rdata.writer.WriteAttributeString("Asset", attach.AssetID.ToString()); | ||||
|                     rdata.writer.WriteEndElement(); | ||||
|                 } | ||||
|                 rdata.writer.WriteEndElement(); | ||||
| 
 | ||||
|                 Primitive.TextureEntry texture = rdata.userAppearance.Texture; | ||||
| 
 | ||||
|                 if (texture != null && (texture.DefaultTexture != null || texture.FaceTextures != null)) | ||||
|                 { | ||||
|                     Rest.Log.DebugFormat("{0} FormatUserAppearance: Formatting textures", MsgId); | ||||
| 
 | ||||
|                     rdata.writer.WriteStartElement("Texture"); | ||||
| 
 | ||||
|                     if (texture.DefaultTexture != null) | ||||
|                     { | ||||
|                         Rest.Log.DebugFormat("{0} FormatUserAppearance: Formatting default texture", MsgId); | ||||
|                         rdata.writer.WriteAttributeString("Default", | ||||
|                             texture.DefaultTexture.TextureID.ToString()); | ||||
|                     } | ||||
| 
 | ||||
|                     if (texture.FaceTextures != null) | ||||
|                     { | ||||
| 
 | ||||
|                         Rest.Log.DebugFormat("{0} FormatUserAppearance: Formatting face textures", MsgId); | ||||
| 
 | ||||
|                         for (int i=0; i<texture.FaceTextures.Length;i++) | ||||
|                         { | ||||
|                             if (texture.FaceTextures[i] != null) | ||||
|                             { | ||||
|                                 rdata.writer.WriteStartElement("Face"); | ||||
|                                 rdata.writer.WriteAttributeString("Index", i.ToString()); | ||||
|                                 rdata.writer.WriteAttributeString("Id", | ||||
|                                         texture.FaceTextures[i].TextureID.ToString()); | ||||
|                                 rdata.writer.WriteEndElement(); | ||||
|                             } | ||||
|                         } | ||||
|                     } | ||||
| 
 | ||||
|                     rdata.writer.WriteEndElement(); | ||||
|                 } | ||||
| 
 | ||||
|                 Rest.Log.DebugFormat("{0} FormatUserAppearance: Formatting visual parameters", MsgId); | ||||
| 
 | ||||
|                 rdata.writer.WriteStartElement("VisualParameters"); | ||||
|                 rdata.writer.WriteBase64(rdata.userAppearance.VisualParams,0, | ||||
|                             rdata.userAppearance.VisualParams.Length); | ||||
|                 rdata.writer.WriteEndElement(); | ||||
|                 rdata.writer.WriteFullEndElement(); | ||||
|             } | ||||
| 
 | ||||
|             Rest.Log.DebugFormat("{0} FormatUserAppearance: completed", MsgId); | ||||
| 
 | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         #region appearance RequestData extension | ||||
| 
 | ||||
|         internal class AppearanceRequestData : RequestData | ||||
|         { | ||||
| 
 | ||||
|             /// <summary> | ||||
|             /// These are the inventory specific request/response state | ||||
|             /// extensions. | ||||
|             /// </summary> | ||||
| 
 | ||||
|             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 | ||||
| 
 | ||||
|     } | ||||
| } | ||||
|  | @ -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 | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// 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. | ||||
|         /// </summary> | ||||
| 
 | ||||
|         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)); | ||||
| 
 | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// 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. | ||||
|         /// </summary> | ||||
|         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("<p> Created asset {0}, UUID {1} <p>", asset.Name, asset.FullID)); | ||||
|                 rdata.Complete(Rest.HttpStatusCodeCreated); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 if (modified) | ||||
|                 { | ||||
|                     rdata.appendStatus(String.Format("<p> Modified asset {0}, UUID {1} <p>", asset.Name, asset.FullID)); | ||||
|                     rdata.Complete(Rest.HttpStatusCodeOK); | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     rdata.Complete(Rest.HttpStatusCodeNoContent); | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             rdata.Respond(String.Format("Asset {0} : Normal completion", rdata.method)); | ||||
| 
 | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// CREATE new item, replace if it exists. URI identifies the context for the item in question. | ||||
|         /// No parameters are required for POST, just thepayload. | ||||
|         /// </summary> | ||||
| 
 | ||||
|         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("<p> Created asset {0}, UUID {1} <p>", asset.Name, asset.FullID)); | ||||
|                 rdata.Complete(Rest.HttpStatusCodeCreated); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 if (modified) | ||||
|                 { | ||||
|                     rdata.appendStatus(String.Format("<p> Modified asset {0}, UUID {1} <p>", asset.Name, asset.FullID)); | ||||
|                     rdata.Complete(Rest.HttpStatusCodeOK); | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     rdata.Complete(Rest.HttpStatusCodeNoContent); | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             rdata.Respond(String.Format("Asset {0} : Normal completion", rdata.method)); | ||||
| 
 | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Asset processing has no special data area requirements. | ||||
|         /// </summary> | ||||
| 
 | ||||
|         internal class AssetRequestData : RequestData | ||||
|         { | ||||
|             internal AssetRequestData(OSHttpRequest request, OSHttpResponse response, string prefix) | ||||
|                 : base(request, response, prefix) | ||||
|             { | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | @ -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 | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// 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. | ||||
|         /// </summary> | ||||
| 
 | ||||
|         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)); | ||||
| 
 | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// 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. | ||||
|         /// </summary> | ||||
|         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("<p> Created file {0} <p>", path)); | ||||
|                 rdata.Complete(Rest.HttpStatusCodeCreated); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 if (modified) | ||||
|                 { | ||||
|                     rdata.appendStatus(String.Format("<p> Modified file {0} <p>", path)); | ||||
|                     rdata.Complete(Rest.HttpStatusCodeOK); | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     rdata.Complete(Rest.HttpStatusCodeNoContent); | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             rdata.Respond(String.Format("File {0} : Normal completion", rdata.method)); | ||||
| 
 | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// CREATE new item, replace if it exists. URI identifies the context for the item in question. | ||||
|         /// No parameters are required for POST, just thepayload. | ||||
|         /// </summary> | ||||
| 
 | ||||
|         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("<p> Created file {0} <p>", path)); | ||||
|                 rdata.Complete(Rest.HttpStatusCodeCreated); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 if (modified) | ||||
|                 { | ||||
|                     rdata.appendStatus(String.Format("<p> Modified file {0} <p>", path)); | ||||
|                     rdata.Complete(Rest.HttpStatusCodeOK); | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     rdata.Complete(Rest.HttpStatusCodeNoContent); | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             rdata.Respond(String.Format("File {0} : Normal completion", rdata.method)); | ||||
| 
 | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// CREATE new item, replace if it exists. URI identifies the context for the item in question. | ||||
|         /// No parameters are required for POST, just thepayload. | ||||
|         /// </summary> | ||||
| 
 | ||||
|         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("<p> Created file {0} <p>", path)); | ||||
|                 rdata.Complete(Rest.HttpStatusCodeCreated); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 if (modified) | ||||
|                 { | ||||
|                     rdata.appendStatus(String.Format("<p> Modified file {0} <p>", path)); | ||||
|                     rdata.Complete(Rest.HttpStatusCodeOK); | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     rdata.Complete(Rest.HttpStatusCodeNoContent); | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             rdata.Respond(String.Format("File {0} : Normal completion", rdata.method)); | ||||
| 
 | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// File processing has no special data area requirements. | ||||
|         /// </summary> | ||||
| 
 | ||||
|         internal class FileRequestData : RequestData | ||||
|         { | ||||
|             internal FileRequestData(OSHttpRequest request, OSHttpResponse response, string prefix) | ||||
|                 : base(request, response, prefix) | ||||
|             { | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | @ -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 | ||||
| { | ||||
|     /// <remarks> | ||||
|     /// 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. | ||||
|     /// </remarks> | ||||
| 
 | ||||
|     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<string,RestMethodHandler>   pathHandlers   = new Dictionary<string,RestMethodHandler>(); | ||||
|         internal Dictionary<string,RestMethodAllocator> pathAllocators = new Dictionary<string,RestMethodAllocator>(); | ||||
|         internal Dictionary<string,RestStreamHandler>   streamHandlers = new Dictionary<string,RestStreamHandler>(); | ||||
| 
 | ||||
|         #region local static state | ||||
| 
 | ||||
|         private static bool  handlersLoaded = false; | ||||
|         private static List<Type>  classes  = new List<Type>(); | ||||
|         private static List<IRest> handlers = new List<IRest>(); | ||||
|         private static Type[]         parms = new Type[0]; | ||||
|         private static Object[]       args  = new Object[0]; | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// 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. | ||||
|         /// </summary> | ||||
| 
 | ||||
|         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 | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// 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. | ||||
|         /// </summary> | ||||
| 
 | ||||
|         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 | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// This method is called by OpenSimMain immediately after loading the | ||||
|         /// plugin and after basic server setup,  but before running any server commands. | ||||
|         /// </summary> | ||||
|         /// <remarks> | ||||
|         /// Note that entries MUST be added to the active configuration files before | ||||
|         /// the plugin can be enabled. | ||||
|         /// </remarks> | ||||
| 
 | ||||
|         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); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// 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. | ||||
|         /// </summary> | ||||
| 
 | ||||
|         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 | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// 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. | ||||
|         /// </summary> | ||||
| 
 | ||||
|         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; | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// 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. | ||||
|         /// </summary> | ||||
| 
 | ||||
|         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 | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// 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 | ||||
|         /// </summary> | ||||
| 
 | ||||
|         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; | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// 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. | ||||
|         /// </summary> | ||||
|         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); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// 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 | ||||
|         /// </summary> | ||||
| 
 | ||||
|         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; | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// 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. | ||||
|         /// </summary> | ||||
| 
 | ||||
|         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); | ||||
|         } | ||||
|     } | ||||
| } | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							|  | @ -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<Type> classes  = new List<Type>(); | ||||
|         private static List<ITest>   tests = new List<ITest>(); | ||||
|         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); | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// 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. | ||||
|         /// </summary> | ||||
| 
 | ||||
|         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; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|     } | ||||
| } | ||||
|  | @ -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 | ||||
| { | ||||
| 
 | ||||
|     /// <summary> | ||||
|     /// 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. | ||||
|     /// </summary> | ||||
| 
 | ||||
|     internal interface ITest | ||||
|     { | ||||
|         void Initialize(); | ||||
|         void Execute(RequestData rdata); | ||||
|         void Close(); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
|  | @ -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 = | ||||
|                 "<html>" | ||||
|               + "<head><title>Remote Command Usage</title></head>" | ||||
|               + "<body>" | ||||
|               + "<p>Supported commands are:</p>" | ||||
|               + "<dl>" | ||||
|               + "<dt>move/avatar-name/x/y/z</dt>" | ||||
|               + "<dd>moves the specified avatar to another location</dd>" | ||||
|               + "</dl>" | ||||
|               + "</body>" | ||||
|               + "</html>" | ||||
|         ; | ||||
|     } | ||||
| } | ||||
|  | @ -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<IRegionSerialiserModule>(); | ||||
|             if (serialiser != null) | ||||
|                 serialiser.SavePrimsToXml2(scene, new StreamWriter(httpResponse.OutputStream), min, max); | ||||
|              | ||||
|             return ""; | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | @ -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 | ||||
|     } | ||||
| } | ||||
|  | @ -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<IRegionSerialiserModule>(); | ||||
|             if (serialiser != null) | ||||
|                 serialiser.LoadPrimsFromXml2(scene, new StringReader(requestBody), true); | ||||
| 
 | ||||
|             return ""; | ||||
|         } | ||||
| 
 | ||||
|         #endregion POST methods | ||||
|     } | ||||
| } | ||||
|  | @ -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("<x>{0}</x><y>{1}</y>", 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; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | @ -1,11 +0,0 @@ | |||
| <Addin id="OpenSim.ApplicationPlugins.Rest.Regions" version="0.1"> | ||||
|     <Runtime> | ||||
|         <Import assembly="OpenSim.ApplicationPlugins.Rest.Regions.dll"/> | ||||
|     </Runtime> | ||||
|     <Dependencies> | ||||
|         <Addin id="OpenSim" version="0.5" /> | ||||
|     </Dependencies> | ||||
|     <Extension path = "/OpenSim/Startup"> | ||||
|         <Plugin id="RestRegions" type="OpenSim.ApplicationPlugins.Rest.Regions.RestRegionPlugin" /> | ||||
|     </Extension> | ||||
| </Addin> | ||||
|  | @ -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 | ||||
|         /// <summary> | ||||
|         /// This method is called by OpenSimMain immediately after loading the | ||||
|         /// plugin and after basic server setup,  but before running any server commands. | ||||
|         /// </summary> | ||||
|         /// <remarks> | ||||
|         /// Note that entries MUST be added to the active configuration files before | ||||
|         /// the plugin can be enabled. | ||||
|         /// </remarks> | ||||
|         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 | ||||
|     } | ||||
| } | ||||
|  | @ -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; | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Return an ever increasing request ID for logging | ||||
|         /// </summary> | ||||
|         protected string RequestID | ||||
|         { | ||||
|             get { return _reqk++.ToString(); } | ||||
|             set { _reqk = Convert.ToInt32(value); } | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Thread-constant message IDs for logging. | ||||
|         /// </summary> | ||||
|         protected string MsgID | ||||
|         { | ||||
|             get { return String.Format("[REST-{0}] #{1}", Name, _threadRequestID); } | ||||
|             set { _threadRequestID = value; } | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Returns true if Rest Plugins are enabled. | ||||
|         /// </summary> | ||||
|         public bool PluginsAreEnabled | ||||
|         { | ||||
|             get { return null != _config; } | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Returns true if specific Rest Plugin is enabled. | ||||
|         /// </summary> | ||||
|         public bool IsEnabled | ||||
|         { | ||||
|             get | ||||
|             { | ||||
|                 return (null != _pluginConfig) && _pluginConfig.GetBoolean("enabled", false); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// OpenSimMain application | ||||
|         /// </summary> | ||||
|         public OpenSimBase App | ||||
|         { | ||||
|             get { return _app; } | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// RPC server | ||||
|         /// </summary> | ||||
|         public BaseHttpServer HttpServer | ||||
|         { | ||||
|             get { return _httpd; } | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// URL prefix to use for all REST handlers | ||||
|         /// </summary> | ||||
|         public string Prefix | ||||
|         { | ||||
|             get { return _prefix; } | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Access to GOD password string | ||||
|         /// </summary> | ||||
|         protected string GodKey | ||||
|         { | ||||
|             get { return _godkey; } | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Configuration of the plugin | ||||
|         /// </summary> | ||||
|         public IConfig Config | ||||
|         { | ||||
|             get { return _pluginConfig; } | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Name of the plugin | ||||
|         /// </summary> | ||||
|         public abstract string Name { get; } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Return the config section name | ||||
|         /// </summary> | ||||
|         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); | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// This method is called by OpenSimMain immediately after loading the | ||||
|         /// plugin and after basic server setup,  but before running any server commands. | ||||
|         /// </summary> | ||||
|         /// <remarks> | ||||
|         /// Note that entries MUST be added to the active configuration files before | ||||
|         /// the plugin can be enabled. | ||||
|         /// </remarks> | ||||
|         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<RestStreamHandler> _handlers = new List<RestStreamHandler>(); | ||||
|         private Dictionary<string, IHttpAgentHandler> _agents = new Dictionary<string, IHttpAgentHandler>(); | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Add a REST stream handler to the underlying HTTP server. | ||||
|         /// </summary> | ||||
|         /// <param name="httpMethod">GET/PUT/POST/DELETE or | ||||
|         /// similar</param> | ||||
|         /// <param name="path">URL prefix</param> | ||||
|         /// <param name="method">RestMethod handler doing the actual work</param> | ||||
|         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); | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Add a powerful Agent handler to the underlying HTTP | ||||
|         /// server. | ||||
|         /// </summary> | ||||
|         /// <param name="agentName">name of agent handler</param> | ||||
|         /// <param name="handler">agent handler method</param> | ||||
|         /// <returns>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. | ||||
|         /// </returns> | ||||
|         public bool AddAgentHandler(string agentName, IHttpAgentHandler handler) | ||||
|         { | ||||
|             if (!IsEnabled) return false; | ||||
|             _agents.Add(agentName, handler); | ||||
| //            return _httpd.AddAgentHandler(agentName, handler); | ||||
|              | ||||
|             return false; | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Remove a powerful Agent handler from the underlying HTTP | ||||
|         /// server. | ||||
|         /// </summary> | ||||
|         /// <param name="agentName">name of agent handler</param> | ||||
|         /// <param name="handler">agent handler method</param> | ||||
|         /// <returns>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. | ||||
|         /// </returns> | ||||
|         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; | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// 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? | ||||
|         /// </summary> | ||||
|         /// <param name="request">HTTP request header</param> | ||||
|         /// <returns>true when the HTTP request came from god.</returns> | ||||
|         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; | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// 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 | ||||
|         /// </summary> | ||||
|         protected bool IsVerifiedUser(IOSHttpRequest request, UUID uuid) | ||||
|         { | ||||
|             // XXX under construction | ||||
|             return false; | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Clean up and remove all handlers that were added earlier. | ||||
|         /// </summary> | ||||
|         public virtual void Close() | ||||
|         { | ||||
|             foreach (RestStreamHandler h in _handlers) | ||||
|             { | ||||
|                 _httpd.RemoveStreamHandler(h.HttpMethod, h.Path); | ||||
|             } | ||||
|             _handlers = null; | ||||
| //            foreach (KeyValuePair<string, IHttpAgentHandler> h in _agents) | ||||
| //            { | ||||
| //                _httpd.RemoveAgentHandler(h.Key, h.Value); | ||||
| //            } | ||||
|             _agents = null; | ||||
|         } | ||||
| 
 | ||||
|         public virtual void Dispose() | ||||
|         { | ||||
|             Close(); | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Return a failure message. | ||||
|         /// </summary> | ||||
|         /// <param name="method">origin of the failure message</param> | ||||
|         /// <param name="message">failure message</param> | ||||
|         /// <remarks>This should probably set a return code as | ||||
|         /// well. (?)</remarks> | ||||
|         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("<error>{0}</error>", m); | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Return a failure message. | ||||
|         /// </summary> | ||||
|         /// <param name="method">origin of the failure message</param> | ||||
|         /// <param name="e">exception causing the failure message</param> | ||||
|         /// <remarks>This should probably set a return code as | ||||
|         /// well. (?)</remarks> | ||||
|         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("<error>{0}</error>", e.Message); | ||||
|         } | ||||
| 
 | ||||
|         #endregion methods | ||||
|     } | ||||
| } | ||||
|  | @ -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(); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | @ -1,276 +0,0 @@ | |||
| <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"> | ||||
| 
 | ||||
| 	<xsd:annotation> | ||||
| 		<xsd:documentation xml:lang="en"> | ||||
| 		Open Simulator Export/Import XML schema | ||||
| 		August 2008 | ||||
| 		</xsd:documentation> | ||||
| 	</xsd:annotation> | ||||
| 
 | ||||
|     <!-- WARNING!!! | ||||
| 		 This is currently a draft, it does not reflect | ||||
| 		 what is exported, nor what will be understood | ||||
| 		 on import. It is included as a working document | ||||
| 		 and this comment will be removed at such time as | ||||
| 		 the schema corresponds to reality. | ||||
| 	 --> | ||||
| 
 | ||||
| 	<!-- | ||||
| 		REST-related information | ||||
| 		Inventory data is always framed by an  | ||||
| 		inventory element. Consists of zero or | ||||
| 		more elements representing either folders | ||||
| 		or items within those folders. The inventory | ||||
| 		element represents the "real" root folder. | ||||
| 	 --> | ||||
| 
 | ||||
| 	<xsd:element name="inventory" type="inventory_ct" /> | ||||
| 
 | ||||
|     <!-- | ||||
|          The inventory complex type is just an arbitrary | ||||
|          sequence of folders and items. In reality it is | ||||
|          typically just folders. Both item and folder  | ||||
|          have corresponding complex types. It is distinct | ||||
|          from folders insofar as it has no other defining | ||||
|          attributes. | ||||
|      --> | ||||
| 
 | ||||
| 	<xsd:complexType name="inventory_ct"> | ||||
| 		<xsd:element name="folder" type="folder_ct" maxOccurs="unbounded"/> | ||||
| 		<xsd:element name="item"   type="item_ct" maxOccurs="unbounded" /> | ||||
| 	</xsd:complexType> | ||||
|   | ||||
| 	<xsd:complexType name="folder_ct"> | ||||
| 		<xsd:attribute name="UUID"         type="uuid_st" /> | ||||
| 		<xsd:attribute name="name"         type="name_st" /> | ||||
| 		<xsd:attribute name="type"         type="folder_type_st" /> | ||||
| 		<xsd:attribute name="description"  type="xsd:string" />	<!-- added --> | ||||
| 		<xsd:attribute name="version" 	   type="unsignedShort" /> | ||||
| 		<xsd:attribute name="owner"        type="uuid_st" /> | ||||
| 
 | ||||
| 		<xsd:attribute name="creator" 	   type="uuid_st" /> <!-- added --> | ||||
| 		<xsd:attribute name="creationdate" type="date_st" /> <!-- added --> | ||||
| 
 | ||||
| 		<xsd:attribute name="parent"  	   type="uuid_st" /> | ||||
| 
 | ||||
| 		<xsd:element   name="permissions"  type="permissions_ct" maxOccurs="unbounded" />	<!-- added --> | ||||
| 		<xsd:element   name="folder"       type="folder_ct"      maxOccurs="unbounded" /> | ||||
| 		<xsd:element   name="item"         type="item_ct"        maxOccurs="unbounded" /> | ||||
| 	</xsd:complexType> | ||||
| 
 | ||||
| 	<xsd:complexType name="item_ct"> | ||||
| 		<xsd:attribute name="UUID"         type="uuid_st" /> | ||||
| 		<xsd:attribute name="name"         type="name_st" /> | ||||
| 		<xsd:attribute name="type"         type="inventory_type_st" /> | ||||
| 		<xsd:attribute name="description"  type="xsd:string" /> | ||||
| 		<xsd:attribute name="version" 	   type="unsignedShort" />	<!-- added --> | ||||
| 		<xsd:attribute name="owner"        type="uuid_st" /> | ||||
| 
 | ||||
| 		<xsd:attribute name="creator" 	   type="uuid_st" /> | ||||
| 		<xsd:attribute name="creationdate" type="date_st" /> | ||||
| 
 | ||||
| 		<xsd:attribute name="folder"  	   type="uuid_st" /> | ||||
| 		<xsd:attribute name="groupid" 	   type="uuid_st" /> | ||||
| 		<xsd:attribute name="groupowned"   type="xsd:boolean" /> | ||||
| 		<xsd:attribute name="saletype"     type="sale_st" /> | ||||
| 		<xsd:attribute name="saleprice"    type="xsd:decimal" /> | ||||
| 
 | ||||
| 		<xsd:element   name="permissions"  type="permissions_ct" maxOccurs="unbounded" /> | ||||
| 	</xsd:complexType> | ||||
| 
 | ||||
| 	<xsd:complexType name="asset_ct"> | ||||
| 		<xsd:attribute name="UUID"         type="uuid_st" /> | ||||
| 		<xsd:attribute name="name"         type="name_st" /> | ||||
| 		<xsd:attribute name="type"         type="asset_type_st" /> | ||||
| 		<xsd:attribute name="description"  type="xsd:string" /> | ||||
| 		<xsd:attribute name="version" 	   type="unsignedShort" />	<!-- added --> | ||||
| 		<xsd:attribute name="owner"        type="uuid_st" /> | ||||
| 
 | ||||
| 		<xsd:attribute name="creator" 	   type="uuid_st" /> | ||||
| 		<xsd:attribute name="creationdate" type="date_st" /> | ||||
| 
 | ||||
| 		<xsd:attribute name="temporary"    type="xsd:boolean" /> | ||||
| 		<xsd:attribute name="local"        type="xsd:boolean" /> | ||||
| 		<xsd:attribute name="inline"       type="xsd:boolean" /> | ||||
| 	</xsd:complexType> | ||||
| 
 | ||||
| 	<!-- Constrained Simple Data types --> | ||||
| 
 | ||||
|     <!-- | ||||
|          We need to specify name as a simple type because on | ||||
|          some platforms it is constrained by a certain length | ||||
|          limitation. For completeness we indicate that whitespace | ||||
|          should be preserved exactly as specified. | ||||
|      --> | ||||
| 
 | ||||
| 	<xsd:simpleType name="name_st"> | ||||
| 		<xsd:restriction base="xsd:string"> | ||||
| 		    <whiteSpace value="preserve" /> | ||||
|             <minLength value="0" /> | ||||
|             <maxLength value="64" /> | ||||
| 		</xsd:restriction> | ||||
| 	</xsd:simpleType> | ||||
| 
 | ||||
|     <!-- | ||||
|          Type information in the folder is meant to indicate | ||||
|          the preferred asset type for this folder. As such, that | ||||
|          currently corresponds to the type values allowed for | ||||
|          assets, however that is not mandated, so for | ||||
|          now at least I'll represent this as a distinct  | ||||
|          enumeration. | ||||
|          This seems inappropriate; it seems like the folder's | ||||
|          content should reflect the InventoryType classifications | ||||
|          rather than the asset types. | ||||
|      --> | ||||
| 
 | ||||
| 	<xsd:simpleType name="folder_type_st"> | ||||
| 		<xsd:restriction base="xsd:string"> | ||||
| 			<xsd:enumeration value="Texture" /> | ||||
| 			<xsd:enumeration value="Sound" /> | ||||
| 			<xsd:enumeration value="CallingCard" /> | ||||
| 			<xsd:enumeration value="Landmark" /> | ||||
| 			<xsd:enumeration value="Script" /> | ||||
| 			<xsd:enumeration value="Clothing" /> | ||||
| 			<xsd:enumeration value="Object" /> | ||||
| 			<xsd:enumeration value="Notecard" /> | ||||
| 			<xsd:enumeration value="LSLText" /> | ||||
| 			<xsd:enumeration value="LSLByteCode" /> | ||||
| 			<xsd:enumeration value="TextureTGA" /> | ||||
| 			<xsd:enumeration value="BodyPart" /> | ||||
| 			<xsd:enumeration value="SoundWAV" /> | ||||
| 			<xsd:enumeration value="ImageTGA" /> | ||||
| 			<xsd:enumeration value="ImageJPEG" /> | ||||
| 			<xsd:enumeration value="Animation" /> | ||||
| 			<xsd:enumeration value="Gesture" /> | ||||
| 			<xsd:enumeration value="Simstate" /> | ||||
| 			<xsd:enumeration value="Unknown" /> | ||||
| 			<xsd:enumeration value="LostAndFoundFolder" /> | ||||
| 			<xsd:enumeration value="SnapshotFolder" /> | ||||
| 			<xsd:enumeration value="TrashFolder" /> | ||||
| 			<xsd:enumeration value="Folder" /> | ||||
| 			<xsd:enumeration value="RootFolder" /> | ||||
| 		</xsd:restriction> | ||||
| 	</xsd:simpleType> | ||||
| 
 | ||||
|     <!-- | ||||
|          Inventory item type designates an asset class, rather | ||||
|          than a specific asset type. For example, "SnapShot" | ||||
|          might include a number of asset types such as JPEG,  | ||||
|          TGA, etc.. This is not a consistent interpretation, | ||||
|          classifications such as LostAndFound are meta-types | ||||
|          relative to asset classes.  | ||||
| 
 | ||||
|          These types should be abstract and not be tied to a  | ||||
|          specific platform. A world's import facility should be | ||||
|          responsible for mapping these to meaningful internal | ||||
|          representations. | ||||
| 
 | ||||
|          These types were based on information in: | ||||
|              libsecondlife/InventoryManager.cs | ||||
|      --> | ||||
| 
 | ||||
| 	<xsd:simpleType name="inventory_type_st"> | ||||
| 		<xsd:restriction base="xsd:string"> | ||||
| 			<xsd:enumeration value="Texture" /> | ||||
| 			<xsd:enumeration value="Sound" /> | ||||
| 			<xsd:enumeration value="CallingCard" /> | ||||
| 			<xsd:enumeration value="Landmark" /> | ||||
| 			<xsd:enumeration value="Script" /> | ||||
| 			<xsd:enumeration value="Clothing" /> | ||||
| 			<xsd:enumeration value="Object" /> | ||||
| 			<xsd:enumeration value="Notecard" /> | ||||
| 			<xsd:enumeration value="LSL" /> | ||||
| 			<xsd:enumeration value="LSLBytecode" /> | ||||
| 			<xsd:enumeration value="TextureTGA" /> | ||||
| 			<xsd:enumeration value="BodyPart" /> | ||||
| 			<xsd:enumeration value="Snapshot" /> | ||||
| 			<xsd:enumeration value="Attachment" /> | ||||
| 			<xsd:enumeration value="Wearable" /> | ||||
| 			<xsd:enumeration value="Animation" /> | ||||
| 			<xsd:enumeration value="Gesture" /> | ||||
| 			<xsd:enumeration value="Folder" /> | ||||
| 			<xsd:enumeration value="Unknown" /> | ||||
| 			<xsd:enumeration value="LostAndFound" /> | ||||
| 			<xsd:enumeration value="Trash" /> | ||||
| 			<xsd:enumeration value="Root" /> | ||||
| 		</xsd:restriction> | ||||
| 	</xsd:simpleType> | ||||
| 
 | ||||
|     <!-- | ||||
|          The asset types seem to be even more disarrayed than | ||||
|          the inventory types. It seems to be little more than | ||||
|          a reiteration of the inventory type information, | ||||
|          which adds little or nothing to the overall data | ||||
|          model. | ||||
| 
 | ||||
|          Of course, given that these are drawn from the | ||||
|          libsecondlife definitions, we aren't at liberty to | ||||
|          simply redefine them in place. But the XML definitions | ||||
|          here could be made more useful. | ||||
| 
 | ||||
|          These types were based on information in: | ||||
|              libsecondlife/AssetManager.cs | ||||
|      --> | ||||
| 
 | ||||
| 	<xsd:simpleType name="asset_type_st"> | ||||
| 		<xsd:restriction base="xsd:string"> | ||||
| 			<xsd:enumeration value="Texture" /> | ||||
| 			<xsd:enumeration value="Sound" /> | ||||
| 			<xsd:enumeration value="CallingCard" /> | ||||
| 			<xsd:enumeration value="Landmark" /> | ||||
| 			<xsd:enumeration value="Script" /> | ||||
| 			<xsd:enumeration value="Clothing" /> | ||||
| 			<xsd:enumeration value="Object" /> | ||||
| 			<xsd:enumeration value="Notecard" /> | ||||
| 			<xsd:enumeration value="LSLText" /> | ||||
| 			<xsd:enumeration value="LSLByteCode" /> | ||||
| 			<xsd:enumeration value="TextureTGA" /> | ||||
| 			<xsd:enumeration value="BodyPart" /> | ||||
| 			<xsd:enumeration value="SoundWAV" /> | ||||
| 			<xsd:enumeration value="ImageTGA" /> | ||||
| 			<xsd:enumeration value="ImageJPEG" /> | ||||
| 			<xsd:enumeration value="Animation" /> | ||||
| 			<xsd:enumeration value="Gesture" /> | ||||
| 			<xsd:enumeration value="Simstate" /> | ||||
| 			<xsd:enumeration value="Unknown" /> | ||||
| 			<xsd:enumeration value="LostAndFoundFolder" /> | ||||
| 			<xsd:enumeration value="SnapshotFolder" /> | ||||
| 			<xsd:enumeration value="TrashFolder" /> | ||||
| 			<xsd:enumeration value="Folder" /> | ||||
| 			<xsd:enumeration value="RootFolder" /> | ||||
| 		</xsd:restriction> | ||||
| 	</xsd:simpleType> | ||||
| 
 | ||||
|     <!-- This is describing the apparent form of a UUID. If | ||||
|          we ever want a more metaphysical definition we'll  | ||||
|          need to add to it. | ||||
|      --> | ||||
| 
 | ||||
| 	<xsd:simpleType name="uuid_st"> | ||||
| 		<xsd:restriction base="xsd:string"> | ||||
| 		    <xsd:pattern value="[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}"/> | ||||
| 		</xsd:restriction> | ||||
| 	</xsd:simpleType> | ||||
| 
 | ||||
|     <!-- This constrains the date representation. Currently | ||||
|          it is simply an integer representing the elapsed | ||||
| 		 ?? since ??. | ||||
|      --> | ||||
| 
 | ||||
| 	<xsd:simpleType name="date_st"> | ||||
| 		<xsd:restriction base="xsd:positiveInteger"> | ||||
| 		</xsd:restriction> | ||||
| 	</xsd:simpleType> | ||||
| 
 | ||||
|     <!-- This constrains the representation of sale price. | ||||
| 		 Currently it is a simple decimal with no unit | ||||
| 		 specified.  | ||||
|          Issues: interoperability. | ||||
|      --> | ||||
| 
 | ||||
| 	<xsd:simpleType name="sale_st"> | ||||
| 		<xsd:restriction base="xsd:decimal"> | ||||
| 		</xsd:restriction> | ||||
| 	</xsd:simpleType> | ||||
| 
 | ||||
| </xsd:schema> | ||||
|  | @ -487,7 +487,9 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
|             { | ||||
|                 try | ||||
|                 { | ||||
|                     SendHTML500(response); | ||||
|                     byte[] buffer500 = SendHTML500(response); | ||||
|                     response.Body.Write(buffer500,0,buffer500.Length); | ||||
|                     response.Body.Close(); | ||||
|                 } | ||||
|                 catch | ||||
|                 { | ||||
|  | @ -720,7 +722,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 | ||||
|             { | ||||
|  | @ -1792,7 +1802,8 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
|             response.SendChunked = false; | ||||
|             response.ContentLength64 = buffer.Length; | ||||
|             response.ContentEncoding = Encoding.UTF8; | ||||
| 
 | ||||
|              | ||||
|                  | ||||
|             return buffer; | ||||
|         } | ||||
| 
 | ||||
|  |  | |||
|  | @ -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; | ||||
| 
 | ||||
|                 // Figure out the yaw value for this much roll. | ||||
|                 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; | ||||
|                 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); | ||||
|                 //     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. 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 * 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); | ||||
|  |  | |||
|  | @ -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<float>("VehicleGroundGravityFudge", "Factor to multiple gravity if a ground vehicle is probably on the ground (0.0 - 1.0)", | ||||
|         new ParameterDefn<float>("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<float>("VehicleAngularBankingTimescaleFudge", "Factor to multiple angular banking timescale. Tune to increase realism.", | ||||
|             60.0f, | ||||
|             (s) => { return VehicleAngularBankingTimescaleFudge; }, | ||||
|             (s,v) => { VehicleAngularBankingTimescaleFudge = v; } ), | ||||
|         new ParameterDefn<bool>("VehicleDebuggingEnable", "Turn on/off vehicle debugging", | ||||
|             false, | ||||
|             (s) => { return VehicleDebuggingEnabled; }, | ||||
|  |  | |||
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							|  | @ -1669,6 +1669,65 @@ | |||
|             A header have been received. | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="T:HttpServer.LocklessQueue`1"> | ||||
|             <summary> | ||||
|             A thread-safe lockless queue that supports multiple readers and  | ||||
|             multiple writers | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="F:HttpServer.LocklessQueue`1.head"> | ||||
|             <summary>Queue head</summary> | ||||
|         </member> | ||||
|         <member name="F:HttpServer.LocklessQueue`1.tail"> | ||||
|             <summary>Queue tail</summary> | ||||
|         </member> | ||||
|         <member name="F:HttpServer.LocklessQueue`1.count"> | ||||
|             <summary>Queue item count</summary> | ||||
|         </member> | ||||
|         <member name="M:HttpServer.LocklessQueue`1.#ctor"> | ||||
|             <summary> | ||||
|             Constructor | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="M:HttpServer.LocklessQueue`1.Enqueue(`0)"> | ||||
|             <summary> | ||||
|             Enqueue an item | ||||
|             </summary> | ||||
|             <param name="item">Item to enqeue</param> | ||||
|         </member> | ||||
|         <member name="M:HttpServer.LocklessQueue`1.TryDequeue(`0@)"> | ||||
|             <summary> | ||||
|             Try to dequeue an item | ||||
|             </summary> | ||||
|             <param name="item">Dequeued item if the dequeue was successful</param> | ||||
|             <returns>True if an item was successfully deqeued, otherwise false</returns> | ||||
|         </member> | ||||
|         <member name="P:HttpServer.LocklessQueue`1.Count"> | ||||
|             <summary>Gets the current number of items in the queue. Since this | ||||
|             is a lockless collection this value should be treated as a close | ||||
|             estimate</summary> | ||||
|         </member> | ||||
|         <member name="T:HttpServer.LocklessQueue`1.SingleLinkNode"> | ||||
|             <summary> | ||||
|             Provides a node container for data in a singly linked list | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="F:HttpServer.LocklessQueue`1.SingleLinkNode.Next"> | ||||
|             <summary>Pointer to the next node in list</summary> | ||||
|         </member> | ||||
|         <member name="F:HttpServer.LocklessQueue`1.SingleLinkNode.Item"> | ||||
|             <summary>The data contained by the node</summary> | ||||
|         </member> | ||||
|         <member name="M:HttpServer.LocklessQueue`1.SingleLinkNode.#ctor"> | ||||
|             <summary> | ||||
|             Constructor | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="M:HttpServer.LocklessQueue`1.SingleLinkNode.#ctor(`0)"> | ||||
|             <summary> | ||||
|             Constructor | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="T:HttpServer.IHttpRequest"> | ||||
|             <summary> | ||||
|             Contains server side HTTP request information. | ||||
|  | @ -2825,6 +2884,11 @@ | |||
|             <param name="protocol">Kind of HTTPS protocol. Usually TLS or SSL.</param> | ||||
|             <returns>A created <see cref="T:HttpServer.IHttpClientContext"/>.</returns> | ||||
|         </member> | ||||
|         <member name="M:HttpServer.IHttpContextFactory.Shutdown"> | ||||
|             <summary> | ||||
|             Server is shutting down so shut down the factory | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="E:HttpServer.IHttpContextFactory.RequestReceived"> | ||||
|             <summary> | ||||
|             A request have been received from one of the contexts. | ||||
|  | @ -2876,6 +2940,11 @@ | |||
|             A creates <see cref="T:HttpServer.IHttpClientContext"/>. | ||||
|             </returns> | ||||
|         </member> | ||||
|         <member name="M:HttpServer.HttpContextFactory.Shutdown"> | ||||
|             <summary> | ||||
|             Server is shutting down so shut down the factory | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="P:HttpServer.HttpContextFactory.UseTraceLogs"> | ||||
|             <summary> | ||||
|              True if detailed trace logs should be written. | ||||
|  | @ -4315,6 +4384,58 @@ | |||
|             </summary> | ||||
|             <param name="message">message describing the error</param> | ||||
|         </member> | ||||
|         <member name="T:HttpServer.ContextTimeoutManager"> | ||||
|             <summary> | ||||
|             Timeout Manager.   Checks for dead clients.  Clients with open connections that are not doing anything.   Closes sessions opened with keepalive. | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="M:HttpServer.ContextTimeoutManager.ProcessContextTimeouts"> | ||||
|             <summary> | ||||
|             Causes the watcher to immediately check the connections.  | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="M:HttpServer.ContextTimeoutManager.EnvironmentTickCount"> | ||||
|             <summary> | ||||
|             Environment.TickCount is an int but it counts all 32 bits so it goes positive | ||||
|             and negative every 24.9 days. This trims down TickCount so it doesn't wrap | ||||
|             for the callers.  | ||||
|             This trims it to a 12 day interval so don't let your frame time get too long. | ||||
|             </summary> | ||||
|             <returns></returns> | ||||
|         </member> | ||||
|         <member name="M:HttpServer.ContextTimeoutManager.EnvironmentTickCountSubtract(System.Int32,System.Int32)"> | ||||
|             <summary> | ||||
|             Environment.TickCount is an int but it counts all 32 bits so it goes positive | ||||
|             and negative every 24.9 days. Subtracts the passed value (previously fetched by | ||||
|             'EnvironmentTickCount()') and accounts for any wrapping. | ||||
|             </summary> | ||||
|             <param name="newValue"></param> | ||||
|             <param name="prevValue"></param> | ||||
|             <returns>subtraction of passed prevValue from current Environment.TickCount</returns> | ||||
|         </member> | ||||
|         <member name="M:HttpServer.ContextTimeoutManager.EnvironmentTickCountAdd(System.Int32,System.Int32)"> | ||||
|             <summary> | ||||
|             Environment.TickCount is an int but it counts all 32 bits so it goes positive | ||||
|             and negative every 24.9 days. Subtracts the passed value (previously fetched by | ||||
|             'EnvironmentTickCount()') and accounts for any wrapping. | ||||
|             </summary> | ||||
|             <param name="newValue"></param> | ||||
|             <param name="prevValue"></param> | ||||
|             <returns>subtraction of passed prevValue from current Environment.TickCount</returns> | ||||
|         </member> | ||||
|         <member name="M:HttpServer.ContextTimeoutManager.EnvironmentTickCountSubtract(System.Int32)"> | ||||
|             <summary> | ||||
|             Environment.TickCount is an int but it counts all 32 bits so it goes positive | ||||
|             and negative every 24.9 days. Subtracts the passed value (previously fetched by | ||||
|             'EnvironmentTickCount()') and accounts for any wrapping. | ||||
|             </summary> | ||||
|             <returns>subtraction of passed prevValue from current Environment.TickCount</returns> | ||||
|         </member> | ||||
|         <member name="T:HttpServer.ContextTimeoutManager.MonitorType"> | ||||
|             <summary> | ||||
|             Use a Thread or a Timer to monitor the ugly | ||||
|             </summary> | ||||
|         </member> | ||||
|         <member name="T:HttpServer.Sessions.MemorySessionStore"> | ||||
|             <summary> | ||||
|             Session store using memory for each session. | ||||
|  |  | |||
							
								
								
									
										115
									
								
								prebuild.xml
								
								
								
								
							
							
						
						
									
										115
									
								
								prebuild.xml
								
								
								
								
							|  | @ -2039,121 +2039,6 @@ | |||
|       </Files> | ||||
|     </Project> | ||||
| 
 | ||||
|     <!-- REST plugins --> | ||||
|     <Project frameworkVersion="v3_5" name="OpenSim.ApplicationPlugins.Rest" path="OpenSim/ApplicationPlugins/Rest" type="Library"> | ||||
|       <Configuration name="Debug"> | ||||
|         <Options> | ||||
|           <OutputPath>../../../bin/</OutputPath> | ||||
|         </Options> | ||||
|       </Configuration> | ||||
|       <Configuration name="Release"> | ||||
|         <Options> | ||||
|           <OutputPath>../../../bin/</OutputPath> | ||||
|         </Options> | ||||
|       </Configuration> | ||||
| 
 | ||||
|       <ReferencePath>../../../bin/</ReferencePath> | ||||
|       <Reference name="Mono.Addins" path="../../../bin/"/> | ||||
|       <Reference name="System"/> | ||||
|       <Reference name="System.Xml"/> | ||||
|       <Reference name="OpenMetaverseTypes" path="../../../bin/"/> | ||||
|       <Reference name="Nini" path="../../../bin/"/> | ||||
|       <Reference name="XMLRPC" path="../../../bin/"/> | ||||
|       <Reference name="OpenSim"/> | ||||
|       <Reference name="OpenSim.Region.ClientStack"/> | ||||
|       <Reference name="OpenSim.Region.Framework"/> | ||||
|       <Reference name="OpenSim.Region.CoreModules"/> | ||||
|       <Reference name="OpenSim.Framework.Communications"/> | ||||
|       <Reference name="OpenSim.Framework"/> | ||||
|       <Reference name="OpenSim.Framework.Servers"/> | ||||
|       <Reference name="OpenSim.Framework.Servers.HttpServer"/> | ||||
|       <Reference name="OpenSim.Framework.Console"/> | ||||
|       <Reference name="log4net" path="../../../bin/"/> | ||||
| 
 | ||||
|       <Files> | ||||
|         <Match pattern="*.cs" recurse="false"/> | ||||
|       </Files> | ||||
|     </Project> | ||||
| 
 | ||||
|     <Project frameworkVersion="v3_5" name="OpenSim.ApplicationPlugins.Rest.Regions" path="OpenSim/ApplicationPlugins/Rest/Regions" type="Library"> | ||||
|       <Configuration name="Debug"> | ||||
|         <Options> | ||||
|           <OutputPath>../../../../bin/</OutputPath> | ||||
|         </Options> | ||||
|       </Configuration> | ||||
|       <Configuration name="Release"> | ||||
|         <Options> | ||||
|           <OutputPath>../../../../bin/</OutputPath> | ||||
|         </Options> | ||||
|       </Configuration> | ||||
| 
 | ||||
|       <ReferencePath>../../../../bin/</ReferencePath> | ||||
|       <Reference name="Mono.Addins" path="../../../../bin/"/> | ||||
|       <Reference name="System"/> | ||||
|       <Reference name="System.Xml"/> | ||||
|       <Reference name="OpenMetaverseTypes" path="../../../../bin/"/> | ||||
|       <Reference name="Nini" path="../../../../bin/"/> | ||||
|       <Reference name="XMLRPC" path="../../../../bin/"/> | ||||
|       <Reference name="OpenSim"/> | ||||
|       <Reference name="OpenSim.Region.Framework"/> | ||||
|       <Reference name="OpenSim.Region.ClientStack"/> | ||||
|       <Reference name="OpenSim.Region.CoreModules"/> | ||||
|       <Reference name="OpenSim.Framework.Communications"/> | ||||
|       <Reference name="OpenSim.Framework"/> | ||||
|       <Reference name="OpenSim.Framework.Servers"/> | ||||
|       <Reference name="OpenSim.Framework.Servers.HttpServer"/> | ||||
|       <Reference name="OpenSim.Framework.Console"/> | ||||
|       <Reference name="OpenSim.ApplicationPlugins.Rest"/> | ||||
|       <Reference name="log4net" path="../../../../bin/"/> | ||||
| 
 | ||||
|       <Files> | ||||
|         <Match pattern="*.cs" recurse="true"/> | ||||
|         <Match buildAction="EmbeddedResource" path="Resources" pattern="*.addin.xml" recurse="true"/> | ||||
|       </Files> | ||||
|     </Project> | ||||
| 
 | ||||
|     <Project frameworkVersion="v3_5" name="OpenSim.ApplicationPlugins.Rest.Inventory" path="OpenSim/ApplicationPlugins/Rest/Inventory" type="Library"> | ||||
|       <Configuration name="Debug"> | ||||
|         <Options> | ||||
|           <OutputPath>../../../../bin/</OutputPath> | ||||
|         </Options> | ||||
|       </Configuration> | ||||
|       <Configuration name="Release"> | ||||
|         <Options> | ||||
|           <OutputPath>../../../../bin/</OutputPath> | ||||
|         </Options> | ||||
|       </Configuration> | ||||
| 
 | ||||
|       <ReferencePath>../../../../bin/</ReferencePath> | ||||
|       <Reference name="Mono.Addins" path="../../../../bin/"/> | ||||
|       <Reference name="System"/> | ||||
|       <Reference name="System.Xml"/> | ||||
|       <Reference name="System.Drawing"/> | ||||
|       <Reference name="OpenMetaverseTypes" path="../../../../bin/"/> | ||||
|       <Reference name="OpenMetaverse" path="../../../../bin/"/> | ||||
|       <Reference name="Nini" path="../../../../bin/"/> | ||||
|       <Reference name="XMLRPC" path="../../../../bin/"/> | ||||
|       <Reference name="OpenSim"/> | ||||
|       <Reference name="OpenSim.Region.Framework"/> | ||||
|       <Reference name="OpenSim.Region.ClientStack"/> | ||||
|       <Reference name="OpenSim.Region.CoreModules"/> | ||||
|       <Reference name="OpenSim.Framework.Communications"/> | ||||
|       <Reference name="OpenSim.Framework"/> | ||||
|       <Reference name="OpenSim.Framework.Servers"/> | ||||
|       <Reference name="OpenSim.Framework.Servers.HttpServer"/> | ||||
|       <Reference name="OpenSim.Framework.Console"/> | ||||
|       <Reference name="OpenSim.Services.Interfaces"/> | ||||
|       <Reference name="OpenSim.ApplicationPlugins.Rest"/> | ||||
|       <Reference name="log4net" path="../../../../bin/"/> | ||||
| 
 | ||||
|       <Files> | ||||
|         <Match pattern="*.cs" recurse="true"/> | ||||
|         <Match buildAction="EmbeddedResource" path="Resources" pattern="*.addin.xml" recurse="true"/> | ||||
|       </Files> | ||||
|     </Project> | ||||
| 
 | ||||
|     <!-- /REST plugins --> | ||||
| 
 | ||||
|     <!-- Scene Server API Example Apps --> | ||||
| 
 | ||||
|     <Project frameworkVersion="v3_5" name="OpenSim.Region.DataSnapshot" path="OpenSim/Region/DataSnapshot" type="Library"> | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	 Melanie
						Melanie