From: Alan Webb <alan_webb@us.ibm.com>
cleanups of the REST inventory code.0.6.0-stable
parent
2b83169c4b
commit
5e83a75815
File diff suppressed because it is too large
Load Diff
|
@ -38,9 +38,11 @@ using Nini.Config;
|
|||
|
||||
namespace OpenSim.ApplicationPlugins.Rest.Inventory
|
||||
{
|
||||
|
||||
public class Rest
|
||||
{
|
||||
internal static readonly log4net.ILog Log =
|
||||
|
||||
internal static readonly log4net.ILog Log =
|
||||
log4net.LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||
|
||||
internal static bool DEBUG = Log.IsDebugEnabled;
|
||||
|
@ -53,7 +55,7 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
|
|||
/// RestHandler class during start-up.
|
||||
/// </summary>
|
||||
|
||||
internal static RestHandler Plugin = null;
|
||||
internal static IRestHandler Plugin = null;
|
||||
internal static OpenSimBase main = null;
|
||||
internal static CommunicationsManager Comms = null;
|
||||
internal static IInventoryServices InventoryServices = null;
|
||||
|
@ -66,10 +68,47 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
|
|||
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 = "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
|
||||
|
||||
/// <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; }
|
||||
|
@ -203,53 +242,97 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
|
|||
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 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";
|
||||
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
|
||||
|
||||
|
@ -372,40 +455,21 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
|
|||
}
|
||||
|
||||
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());
|
||||
return StringToBase64(CreationDate + Guid.NewGuid().ToString());
|
||||
}
|
||||
|
||||
// Dump he specified data stream;
|
||||
|
||||
public static void Dump(byte[] data)
|
||||
{
|
||||
|
||||
char[] buffer = new char[Rest.DumpLineSize];
|
||||
int cc = 0;
|
||||
|
||||
|
@ -415,7 +479,6 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
|
|||
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"));
|
||||
|
||||
|
@ -431,6 +494,7 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
|
|||
Console.Write(" |"+(new String(buffer))+"|");
|
||||
cc = 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Finish off any incomplete line
|
||||
|
@ -440,7 +504,6 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
|
|||
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] = ' ';
|
||||
}
|
||||
|
@ -450,13 +513,16 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
|
|||
{
|
||||
Console.Write("\n");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Local exception type
|
||||
|
||||
public class RestException : Exception
|
||||
{
|
||||
|
||||
internal int statusCode;
|
||||
internal string statusDesc;
|
||||
internal string httpmethod;
|
||||
|
@ -466,4 +532,5 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
|
|||
{
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
using libsecondlife;
|
||||
|
@ -39,8 +40,10 @@ using OpenSim.Framework.Communications.Cache;
|
|||
|
||||
namespace OpenSim.ApplicationPlugins.Rest.Inventory
|
||||
{
|
||||
|
||||
public class RestAssetServices : IRest
|
||||
{
|
||||
|
||||
private bool enabled = false;
|
||||
private string qPrefix = "assets";
|
||||
|
||||
|
@ -49,6 +52,7 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
|
|||
|
||||
public RestAssetServices()
|
||||
{
|
||||
|
||||
Rest.Log.InfoFormat("{0} Asset services initializing", MsgId);
|
||||
Rest.Log.InfoFormat("{0} Using REST Implementation Version {1}", MsgId, Rest.Version);
|
||||
|
||||
|
@ -69,6 +73,7 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
|
|||
enabled = true;
|
||||
|
||||
Rest.Log.InfoFormat("{0} Asset services initialization complete", MsgId);
|
||||
|
||||
}
|
||||
|
||||
// Post-construction, pre-enabled initialization opportunity
|
||||
|
@ -106,8 +111,8 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
|
|||
|
||||
private void DoAsset(RequestData rparm)
|
||||
{
|
||||
if (!enabled)
|
||||
return;
|
||||
|
||||
if (!enabled) return;
|
||||
|
||||
AssetRequestData rdata = (AssetRequestData) rparm;
|
||||
|
||||
|
@ -131,7 +136,7 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
|
|||
{
|
||||
if (!rdata.IsAuthenticated)
|
||||
{
|
||||
rdata.Fail(Rest.HttpStatusCodeNotAuthorized, Rest.HttpStatusDescNotAuthorized);
|
||||
rdata.Fail(Rest.HttpStatusCodeNotAuthorized, String.Format("user \"{0}\" could not be authenticated"));
|
||||
}
|
||||
}
|
||||
catch (RestException e)
|
||||
|
@ -155,7 +160,7 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
|
|||
// the parameters we need, fail the request. Parameters do NOT include
|
||||
// any supplied query values.
|
||||
|
||||
if (rdata.parameters.Length > 0)
|
||||
if (rdata.Parameters.Length > 0)
|
||||
{
|
||||
switch (rdata.method)
|
||||
{
|
||||
|
@ -170,24 +175,25 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
|
|||
default :
|
||||
Rest.Log.WarnFormat("{0} Asset: Method not supported: {1}",
|
||||
MsgId, rdata.method);
|
||||
rdata.Fail(Rest.HttpStatusCodeBadRequest,
|
||||
Rest.HttpStatusDescBadRequest);
|
||||
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, Rest.HttpStatusDescBadRequest);
|
||||
rdata.Fail(Rest.HttpStatusCodeBadRequest, "no agent information provided");
|
||||
}
|
||||
|
||||
Rest.Log.DebugFormat("{0} REST Asset handler EXIT", MsgId);
|
||||
|
||||
}
|
||||
|
||||
#endregion Interface
|
||||
|
||||
private void DoGet(AssetRequestData rdata)
|
||||
{
|
||||
|
||||
bool istexture = false;
|
||||
|
||||
Rest.Log.DebugFormat("{0} REST Asset handler, Method = <{1}> ENTRY", MsgId, rdata.method);
|
||||
|
@ -195,14 +201,16 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
|
|||
// The only parameter we accept is an LLUUID for
|
||||
// the asset
|
||||
|
||||
if (rdata.parameters.Length == 1)
|
||||
if (rdata.Parameters.Length == 1)
|
||||
{
|
||||
LLUUID uuid = new LLUUID(rdata.parameters[0]);
|
||||
|
||||
LLUUID uuid = new LLUUID(rdata.Parameters[0]);
|
||||
AssetBase asset = Rest.AssetServices.GetAsset(uuid, istexture);
|
||||
|
||||
if (asset != null)
|
||||
{
|
||||
Rest.Log.DebugFormat("{0} Asset located <{1}>", MsgId, rdata.parameters[0]);
|
||||
|
||||
Rest.Log.DebugFormat("{0} Asset located <{1}>", MsgId, rdata.Parameters[0]);
|
||||
|
||||
rdata.initXmlWriter();
|
||||
|
||||
|
@ -218,17 +226,18 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
|
|||
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,
|
||||
Rest.HttpStatusDescNotFound);
|
||||
rdata.Fail(Rest.HttpStatusCodeNotFound, "invalid parameters");
|
||||
}
|
||||
}
|
||||
|
||||
rdata.Complete();
|
||||
rdata.Respond("Asset " + rdata.method + ": Normal completion");
|
||||
|
||||
}
|
||||
|
||||
private void DoPut(AssetRequestData rdata)
|
||||
|
@ -238,7 +247,7 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
|
|||
// The only parameter we accept is an LLUUID for
|
||||
// the asset
|
||||
|
||||
if (rdata.parameters.Length == 1)
|
||||
if (rdata.Parameters.Length == 1)
|
||||
{
|
||||
rdata.initXmlReader();
|
||||
XmlReader xml = rdata.reader;
|
||||
|
@ -246,12 +255,11 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
|
|||
if (!xml.ReadToFollowing("Asset"))
|
||||
{
|
||||
Rest.Log.DebugFormat("{0} Invalid request data: <{1}>", MsgId, rdata.path);
|
||||
rdata.Fail(Rest.HttpStatusCodeBadRequest,
|
||||
Rest.HttpStatusDescBadRequest);
|
||||
rdata.Fail(Rest.HttpStatusCodeBadRequest,"invalid request data");
|
||||
}
|
||||
|
||||
AssetBase asset = new AssetBase();
|
||||
asset.ID = rdata.parameters[0];
|
||||
asset.ID = rdata.Parameters[0];
|
||||
asset.Name = xml.GetAttribute("name");
|
||||
asset.Description = xml.GetAttribute("desc");
|
||||
asset.Type = SByte.Parse(xml.GetAttribute("type"));
|
||||
|
@ -264,12 +272,12 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
|
|||
else
|
||||
{
|
||||
Rest.Log.DebugFormat("{0} Invalid parameters: <{1}>", MsgId, rdata.path);
|
||||
rdata.Fail(Rest.HttpStatusCodeNotFound,
|
||||
Rest.HttpStatusDescNotFound);
|
||||
rdata.Fail(Rest.HttpStatusCodeNotFound, "invalid parameters");
|
||||
}
|
||||
|
||||
rdata.Complete();
|
||||
rdata.Respond("Asset " + rdata.method + ": Normal completion");
|
||||
|
||||
}
|
||||
|
||||
internal class AssetRequestData : RequestData
|
||||
|
@ -279,5 +287,6 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
|
|||
{
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
using System;
|
||||
|
@ -34,8 +35,27 @@ using OpenSim.ApplicationPlugins.Rest;
|
|||
|
||||
namespace OpenSim.ApplicationPlugins.Rest.Inventory
|
||||
{
|
||||
public class RestHandler : RestPlugin, IHttpAgentHandler
|
||||
|
||||
/// <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
|
||||
{
|
||||
|
||||
/// <remarks>
|
||||
/// The handler delegates are not noteworthy. The allocator allows
|
||||
/// a given handler to optionally subclass the base RequestData
|
||||
|
@ -43,8 +63,8 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
|
|||
/// needed.
|
||||
/// </remarks>
|
||||
|
||||
internal delegate void RestMethodHandler(RequestData rdata);
|
||||
internal delegate RequestData RestMethodAllocator(OSHttpRequest request, OSHttpResponse response);
|
||||
// internal delegate void RestMethodHandler(RequestData rdata);
|
||||
// internal delegate RequestData RestMethodAllocator(OSHttpRequest request, OSHttpResponse response);
|
||||
|
||||
// Handler tables: both stream and REST are supported. The path handlers and their
|
||||
// respective allocators are stored in separate tables.
|
||||
|
@ -76,6 +96,7 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
|
|||
|
||||
static RestHandler()
|
||||
{
|
||||
|
||||
Module[] mods = Assembly.GetExecutingAssembly().GetModules();
|
||||
|
||||
foreach (Module m in mods)
|
||||
|
@ -97,6 +118,7 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endregion local static state
|
||||
|
@ -124,6 +146,7 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
|
|||
{
|
||||
if (!handlersLoaded)
|
||||
{
|
||||
|
||||
ConstructorInfo ci;
|
||||
Object ht;
|
||||
|
||||
|
@ -171,12 +194,12 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
|
|||
// classes in our assembly and the base
|
||||
// names are protected.
|
||||
|
||||
internal string MsgId
|
||||
public string MsgId
|
||||
{
|
||||
get { return base.MsgID; }
|
||||
}
|
||||
|
||||
internal string RequestId
|
||||
public string RequestId
|
||||
{
|
||||
get { return base.RequestID; }
|
||||
}
|
||||
|
@ -198,6 +221,7 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
|
|||
{
|
||||
try
|
||||
{
|
||||
|
||||
// This plugin will only be enabled if the broader
|
||||
// REST plugin mechanism is enabled.
|
||||
|
||||
|
@ -221,7 +245,7 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
|
|||
|
||||
Rest.main = openSim;
|
||||
Rest.Plugin = this;
|
||||
Rest.Comms = App.CommunicationsManager;
|
||||
Rest.Comms = Rest.main.CommunicationsManager;
|
||||
Rest.UserServices = Rest.Comms.UserService;
|
||||
Rest.InventoryServices = Rest.Comms.InventoryService;
|
||||
Rest.AssetServices = Rest.Comms.AssetCache;
|
||||
|
@ -234,7 +258,9 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
|
|||
Rest.ExtendedEscape = Rest.Config.GetBoolean("extended-escape",true);
|
||||
Rest.Realm = Rest.Config.GetString("realm","OpenSim REST");
|
||||
Rest.DumpAsset = Rest.Config.GetBoolean("dump-asset",false);
|
||||
Rest.Fill = Rest.Config.GetBoolean("path-fill",true);
|
||||
Rest.DumpLineSize = Rest.Config.GetInt("dump-line-size",32);
|
||||
Rest.FlushEnabled = Rest.Config.GetBoolean("flush-on-error",true);
|
||||
|
||||
Rest.Log.InfoFormat("{0} Authentication is {1}required", MsgId,
|
||||
(Rest.Authenticate ? "" : "not "));
|
||||
|
@ -248,6 +274,11 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
|
|||
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.Prefix = Rest.UrlPathSeparator+Rest.Prefix;
|
||||
|
||||
// If data dumping is requested, report on the chosen line
|
||||
// length.
|
||||
|
||||
|
@ -308,6 +339,7 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
|
|||
{
|
||||
Rest.Log.ErrorFormat("{0} Plugin initialization has failed: {1}", MsgId, e.Message);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -322,6 +354,7 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
|
|||
|
||||
public override void Close()
|
||||
{
|
||||
|
||||
Rest.Log.InfoFormat("{0} Plugin is terminating", MsgId);
|
||||
|
||||
try
|
||||
|
@ -334,6 +367,7 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
|
|||
{
|
||||
handler.Close();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endregion overriding methods
|
||||
|
@ -352,25 +386,57 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
|
|||
{
|
||||
string path = request.RawUrl;
|
||||
|
||||
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))
|
||||
{
|
||||
return (path.Length == key.Length ||
|
||||
path.Substring(key.Length, 1) == Rest.UrlPathSeparator);
|
||||
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))
|
||||
{
|
||||
return true;
|
||||
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)
|
||||
{
|
||||
|
@ -415,8 +481,8 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
|
|||
|
||||
try
|
||||
{
|
||||
handled = FindPathHandler(request, response) ||
|
||||
FindStreamHandler(request, response);
|
||||
handled = ( FindPathHandler(request, response) ||
|
||||
FindStreamHandler(request, response) );
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
@ -430,6 +496,7 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
|
|||
Rest.Log.DebugFormat("{0} EXIT", MsgId);
|
||||
|
||||
return handled;
|
||||
|
||||
}
|
||||
|
||||
#endregion interface methods
|
||||
|
@ -477,6 +544,7 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
|
|||
}
|
||||
|
||||
return rdata.handled;
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -489,6 +557,7 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
|
|||
|
||||
public void AddStreamHandler(string httpMethod, string path, RestMethod method)
|
||||
{
|
||||
|
||||
if (!IsEnabled)
|
||||
{
|
||||
return;
|
||||
|
@ -512,6 +581,7 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
|
|||
{
|
||||
Rest.Log.WarnFormat("{0} Ignoring duplicate handler for {1}", MsgId, path);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -526,6 +596,7 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
|
|||
|
||||
internal bool FindPathHandler(OSHttpRequest request, OSHttpResponse response)
|
||||
{
|
||||
|
||||
RequestData rdata = null;
|
||||
string bestMatch = null;
|
||||
|
||||
|
@ -551,6 +622,7 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
|
|||
|
||||
if (!String.IsNullOrEmpty(bestMatch))
|
||||
{
|
||||
|
||||
rdata = pathAllocators[bestMatch](request, response);
|
||||
|
||||
Rest.Log.DebugFormat("{0} Path based REST handler matched with <{1}>", MsgId, bestMatch);
|
||||
|
@ -567,9 +639,11 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
|
|||
{
|
||||
Rest.Log.WarnFormat("{0} Request failed: {1}", MsgId, r.Message);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return (rdata == null) ? false : rdata.handled;
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -577,8 +651,9 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
|
|||
/// path as a key. If an entry already exists, it is replaced by the new one.
|
||||
/// </summary>
|
||||
|
||||
internal void AddPathHandler(RestMethodHandler mh, string path, RestMethodAllocator ra)
|
||||
public void AddPathHandler(RestMethodHandler mh, string path, RestMethodAllocator ra)
|
||||
{
|
||||
|
||||
if (!IsEnabled)
|
||||
{
|
||||
return;
|
||||
|
@ -600,6 +675,8 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
|
|||
|
||||
pathHandlers.Add(path, mh);
|
||||
pathAllocators.Add(path, ra);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -140,7 +140,8 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
|
|||
{
|
||||
if (!rdata.IsAuthenticated)
|
||||
{
|
||||
rdata.Fail(Rest.HttpStatusCodeNotAuthorized, Rest.HttpStatusDescNotAuthorized);
|
||||
rdata.Fail(Rest.HttpStatusCodeNotAuthorized,
|
||||
String.Format("user \"{0}\" could not be authenticated", rdata.userName));
|
||||
}
|
||||
}
|
||||
catch (RestException e)
|
||||
|
@ -160,10 +161,10 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
|
|||
|
||||
// Check that a test was specified
|
||||
|
||||
if (rdata.parameters.Length < 1)
|
||||
if (rdata.Parameters.Length < 1)
|
||||
{
|
||||
Rest.Log.DebugFormat("{0} Insufficient parameters", MsgId);
|
||||
rdata.Fail(Rest.HttpStatusCodeBadRequest, Rest.HttpStatusDescBadRequest);
|
||||
rdata.Fail(Rest.HttpStatusCodeBadRequest, "not enough parameters");
|
||||
}
|
||||
|
||||
// Select the test
|
||||
|
@ -180,8 +181,8 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
|
|||
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[1];
|
||||
private static Object[] args = new Object[1];
|
||||
private static Type[] parms = new Type[0];
|
||||
private static Object[] args = new Object[0];
|
||||
|
||||
static RestTestServices()
|
||||
{
|
||||
|
@ -191,9 +192,16 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
|
|||
Type[] types = m.GetTypes();
|
||||
foreach (Type t in types)
|
||||
{
|
||||
if (t.GetInterface("ITest") != null)
|
||||
try
|
||||
{
|
||||
classes.Add(t);
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -205,27 +213,38 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
|
|||
/// 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)
|
||||
{
|
||||
parms[0] = this.GetType();
|
||||
args[0] = this;
|
||||
|
||||
ConstructorInfo ci;
|
||||
Object ht;
|
||||
|
||||
foreach (Type t in classes)
|
||||
{
|
||||
ci = t.GetConstructor(parms);
|
||||
ht = ci.Invoke(args);
|
||||
tests.Add((ITest)ht);
|
||||
try
|
||||
{
|
||||
if (t.GetInterface("ITest") != null)
|
||||
{
|
||||
ci = t.GetConstructor(parms);
|
||||
ht = ci.Invoke(args);
|
||||
tests.Add((ITest)ht);
|
||||
Rest.Log.WarnFormat("{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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue