From: Alan Webb <alan_webb@us.ibm.com>

cleanups of the REST inventory code.
0.6.0-stable
Dr Scofield 2008-08-20 10:11:11 +00:00
parent 2b83169c4b
commit 5e83a75815
6 changed files with 1609 additions and 931 deletions

File diff suppressed because it is too large Load Diff

View File

@ -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
{
}
}
}

View File

@ -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
{
}
}
}
}

View File

@ -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);
}
}
}

View File

@ -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;
}
}
}
}
}