/* * Copyright (c) Contributors, http://opensimulator.org/ * See CONTRIBUTORS.TXT for a full list of copyright holders. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the OpenSim Project nor the * names of its contributors may be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ using System; using System.Collections.Generic; using System.Reflection; using System.Text; using OpenSim.Framework; using OpenSim.Framework.Servers; using OpenSim.Framework.Communications; using OpenSim.Framework.Communications.Cache; using Nini.Config; namespace OpenSim.ApplicationPlugins.Rest.Inventory { public class Rest { internal static readonly log4net.ILog Log = log4net.LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); internal static bool DEBUG = Log.IsDebugEnabled; /// /// 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. /// internal static RestHandler Plugin = null; internal static OpenSimBase main = null; internal static CommunicationsManager Comms = null; internal static IInventoryServices InventoryServices = null; internal static IUserService UserServices = null; internal static AssetCache AssetServices = 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 string Realm = "REST"; internal static int CreationDate = (int) (DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalSeconds; internal static int DumpLineSize = 32; // Should be a multiple of 16 or (possibly) 4 internal static string MsgId { get { return Plugin.MsgId; } } internal static string RequestId { get { return Plugin.RequestId; } } internal static Encoding Encoding = Encoding.UTF8; /// /// 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. /// public static readonly float Version = 1.0F; public const string Name = "REST 1.0"; /// /// Currently defined HTTP methods. /// Only GET and HEAD are required to be /// supported by all servers. See Respond /// to see how these are handled. /// // 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; // HTTP Status Descriptions (in status code order) public const string HttpStatusDescContinue = "Continue Request"; // 100 public const string HttpStatusDescSwitchingProtocols = "Switching Protocols"; // 101 public const string HttpStatusDescOK = "OK"; public const string HttpStatusDescCreated = "CREATED"; public const string HttpStatusDescAccepted = "ACCEPTED"; public const string HttpStatusDescNonAuthoritative = "NON-AUTHORITATIVE INFORMATION"; public const string HttpStatusDescNoContent = "NO CONTENT"; public const string HttpStatusDescResetContent = "RESET CONTENT"; public const string HttpStatusDescPartialContent = "PARTIAL CONTENT"; public const string HttpStatusDescMultipleChoices = "MULTIPLE CHOICES"; public const string HttpStatusDescPermanentRedirect = "PERMANENT REDIRECT"; public const string HttpStatusDescFound = "FOUND"; public const string HttpStatusDescSeeOther = "SEE OTHER"; public const string HttpStatusDescNotModified = "NOT MODIFIED"; public const string HttpStatusDescUseProxy = "USE PROXY"; public const string HttpStatusDescReserved306 = "RESERVED CODE 306"; public const string HttpStatusDescTemporaryRedirect = "TEMPORARY REDIRECT"; public const string HttpStatusDescBadRequest = "BAD REQUEST"; public const string HttpStatusDescNotAuthorized = "NOT AUTHORIZED"; public const string HttpStatusDescPaymentRequired = "PAYMENT REQUIRED"; public const string HttpStatusDescForbidden = "FORBIDDEN"; public const string HttpStatusDescNotFound = "NOT FOUND"; public const string HttpStatusDescMethodNotAllowed = "METHOD NOT ALLOWED"; public const string HttpStatusDescNotAcceptable = "NOT ACCEPTABLE"; public const string HttpStatusDescProxyAuthenticate = "PROXY AUTHENTICATION REQUIRED"; public const string HttpStatusDescTimeOut = "TIMEOUT"; public const string HttpStatusDescConflict = "CONFLICT"; public const string HttpStatusDescGone = "GONE"; public const string HttpStatusDescLengthRequired = "LENGTH REQUIRED"; public const string HttpStatusDescPreconditionFailed = "PRECONDITION FAILED"; public const string HttpStatusDescEntityTooLarge = "ENTITY TOO LARGE"; public const string HttpStatusDescUriTooLarge = "URI TOO LARGE"; public const string HttpStatusDescUnsupportedMedia = "UNSUPPORTED MEDIA"; public const string HttpStatusDescRangeNotSatisfied = "RANGE NOT SATISFIED"; public const string HttpStatusDescExpectationFailed = "EXPECTATION FAILED"; public const string HttpStatusDescServerError = "SERVER ERROR"; public const string HttpStatusDescNotImplemented = "NOT IMPLEMENTED"; public const string HttpStatusDescBadGateway = "BAD GATEWAY"; public const string HttpStatusDescServiceUnavailable = "SERVICE UNAVAILABLE"; public const string HttpStatusDescGatewayTimeout = "GATEWAY TIMEOUT"; public const string HttpStatusDescHttpVersionError = "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"; /// /// Supported authentication schemes /// public const string AS_BASIC = "Basic"; public const string AS_DIGEST = "Digest"; /// Supported Digest algorithms public const string Digest_MD5 = "MD5"; // assumedd efault if omitted public const string Digest_MD5Sess = "MD5-sess"; public const string Qop_Auth = "auth"; public const string Qop_Int = "auth-int"; /// Utility routines public static string StringToBase64(string str) { try { byte[] encData_byte = new byte[str.Length]; encData_byte = Encoding.UTF8.GetBytes(str); return Convert.ToBase64String(encData_byte); } catch { return String.Empty; } } public static string Base64ToString(string str) { UTF8Encoding encoder = new UTF8Encoding(); Decoder utf8Decode = encoder.GetDecoder(); try { byte[] todecode_byte = Convert.FromBase64String(str); int charCount = utf8Decode.GetCharCount(todecode_byte, 0, todecode_byte.Length); char[] decoded_char = new char[charCount]; utf8Decode.GetChars(todecode_byte, 0, todecode_byte.Length, decoded_char, 0); return new String(decoded_char); } 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; } public static string Int2Hex8(int val) { string res = String.Empty; for (int i = 0; i < 8; i++) { res = (val % 16) + res; val = val / 16; } return res; } public static string ToHex32(int val) { return String.Empty; } public static string ToHex32(string val) { return String.Empty; } // Nonce management public static string NonceGenerator() { return StringToBase64(Guid.NewGuid().ToString()); } // Dump he specified data stream; public static void Dump(byte[] data) { char[] buffer = new char[Rest.DumpLineSize]; int cc = 0; for (int i = 0; i < data.Length; i++) { if (i % Rest.DumpLineSize == 0) Console.Write("\n{0}: ",i.ToString("d8")); if (i % 4 == 0) Console.Write(" "); // if (i%16 == 0) Console.Write(" "); Console.Write("{0}",data[i].ToString("x2")); if (data[i] < 127 && data[i] > 31) buffer[i % Rest.DumpLineSize] = (char) data[i]; else buffer[i % Rest.DumpLineSize] = '.'; cc++; if (i != 0 && (i + 1) % Rest.DumpLineSize == 0) { Console.Write(" |"+(new String(buffer))+"|"); cc = 0; } } // Finish off any incomplete line if (cc != 0) { for (int i = cc ; i < Rest.DumpLineSize; i++) { if (i % 4 == 0) Console.Write(" "); // if (i%16 == 0) Console.Write(" "); Console.Write(" "); buffer[i % Rest.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) { } } }