aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorDr Scofield2008-10-20 18:07:06 +0000
committerDr Scofield2008-10-20 18:07:06 +0000
commit12042cdc2b53e581ace6a017d9b17bd763a544b2 (patch)
tree0d99aa0e5dc5349d420c820c2c78c59f3228957f
parentactually enabling SaveOAR XmlRpc ;-) (diff)
downloadopensim-SC-12042cdc2b53e581ace6a017d9b17bd763a544b2.zip
opensim-SC-12042cdc2b53e581ace6a017d9b17bd763a544b2.tar.gz
opensim-SC-12042cdc2b53e581ace6a017d9b17bd763a544b2.tar.bz2
opensim-SC-12042cdc2b53e581ace6a017d9b17bd763a544b2.tar.xz
From: Alan Webb <alan_webb@us.ibm.com>
cleanups and assorted fixes to REST inventory, asset, and appearance services.
-rw-r--r--OpenSim/ApplicationPlugins/Rest/Inventory/IRestHandler.cs7
-rw-r--r--OpenSim/ApplicationPlugins/Rest/Inventory/RequestData.cs19
-rw-r--r--OpenSim/ApplicationPlugins/Rest/Inventory/Rest.cs35
-rw-r--r--OpenSim/ApplicationPlugins/Rest/Inventory/RestAppearanceServices.cs15
-rw-r--r--OpenSim/ApplicationPlugins/Rest/Inventory/RestAssetServices.cs9
-rw-r--r--OpenSim/ApplicationPlugins/Rest/Inventory/RestHandler.cs43
-rw-r--r--OpenSim/ApplicationPlugins/Rest/Inventory/RestInventoryServices.cs87
-rw-r--r--OpenSim/Framework/Communications/Cache/LibraryRootFolder.cs10
8 files changed, 160 insertions, 65 deletions
diff --git a/OpenSim/ApplicationPlugins/Rest/Inventory/IRestHandler.cs b/OpenSim/ApplicationPlugins/Rest/Inventory/IRestHandler.cs
index 82dc2e4..997c2d3 100644
--- a/OpenSim/ApplicationPlugins/Rest/Inventory/IRestHandler.cs
+++ b/OpenSim/ApplicationPlugins/Rest/Inventory/IRestHandler.cs
@@ -42,11 +42,8 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
42 public delegate RequestData RestMethodAllocator(OSHttpRequest request, OSHttpResponse response, string path); 42 public delegate RequestData RestMethodAllocator(OSHttpRequest request, OSHttpResponse response, string path);
43 43
44 /// <summary> 44 /// <summary>
45 /// This interface represents the boundary between the general purpose 45 /// This interface exports the generic plugin-handling services
46 /// REST plugin handling, and the functionally specific handlers. The 46 /// available to each loaded REST services module (IRest implementation)
47 /// handler knows only to initialize and terminate all such handlers
48 /// that it finds. Implementing this interface identifies the class as
49 /// a REST handler implementation.
50 /// </summary> 47 /// </summary>
51 48
52 internal interface IRestHandler 49 internal interface IRestHandler
diff --git a/OpenSim/ApplicationPlugins/Rest/Inventory/RequestData.cs b/OpenSim/ApplicationPlugins/Rest/Inventory/RequestData.cs
index 081327e..20e619a 100644
--- a/OpenSim/ApplicationPlugins/Rest/Inventory/RequestData.cs
+++ b/OpenSim/ApplicationPlugins/Rest/Inventory/RequestData.cs
@@ -167,7 +167,7 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
167 // 167 //
168 168
169 internal bool authenticated = false; 169 internal bool authenticated = false;
170 internal string scheme = null; 170 internal string scheme = Rest.Scheme;
171 internal string realm = Rest.Realm; 171 internal string realm = Rest.Realm;
172 internal string domain = null; 172 internal string domain = null;
173 internal string nonce = null; 173 internal string nonce = null;
@@ -287,11 +287,12 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
287 287
288 request = p_request; 288 request = p_request;
289 response = p_response; 289 response = p_response;
290 qprefix = p_qprefix; 290 qprefix = p_qprefix;
291 291
292 sbuilder.Length = 0; 292 sbuilder.Length = 0;
293 293
294 encoding = request.ContentEncoding; 294 encoding = request.ContentEncoding;
295
295 if (encoding == null) 296 if (encoding == null)
296 { 297 {
297 encoding = Rest.Encoding; 298 encoding = Rest.Encoding;
@@ -448,9 +449,10 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
448 449
449 if (realm != null) 450 if (realm != null)
450 { 451 {
451 sbuilder.Append(" realm=\""); 452 sbuilder.Append(" realm=");
453 sbuilder.Append(Rest.CS_DQUOTE);
452 sbuilder.Append(realm); 454 sbuilder.Append(realm);
453 sbuilder.Append("\""); 455 sbuilder.Append(Rest.CS_DQUOTE);
454 } 456 }
455 AddHeader(Rest.HttpHeaderWWWAuthenticate,sbuilder.ToString()); 457 AddHeader(Rest.HttpHeaderWWWAuthenticate,sbuilder.ToString());
456 } 458 }
@@ -677,7 +679,7 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
677 679
678 UserProfileData udata = Rest.UserServices.GetUserProfile(first, last); 680 UserProfileData udata = Rest.UserServices.GetUserProfile(first, last);
679 681
680 // If we don;t recognize the user id, perhaps it is god? 682 // If we don't recognize the user id, perhaps it is god?
681 683
682 if (udata == null) 684 if (udata == null)
683 return pass == Rest.GodKey; 685 return pass == Rest.GodKey;
@@ -800,6 +802,7 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
800 if (!authparms.ContainsKey("cnonce")) 802 if (!authparms.ContainsKey("cnonce"))
801 { 803 {
802 Rest.Log.WarnFormat("{0} Authentication failed: cnonce missing", MsgId); 804 Rest.Log.WarnFormat("{0} Authentication failed: cnonce missing", MsgId);
805 Fail(Rest.HttpStatusCodeBadRequest);
803 break; 806 break;
804 } 807 }
805 808
@@ -808,6 +811,7 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
808 if (!authparms.TryGetValue("nc", out nck) || nck == null) 811 if (!authparms.TryGetValue("nc", out nck) || nck == null)
809 { 812 {
810 Rest.Log.WarnFormat("{0} Authentication failed: cnonce counter missing", MsgId); 813 Rest.Log.WarnFormat("{0} Authentication failed: cnonce counter missing", MsgId);
814 Fail(Rest.HttpStatusCodeBadRequest);
811 break; 815 break;
812 } 816 }
813 817
@@ -820,6 +824,7 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
820 if (Rest.Hex2Int(ncl) >= Rest.Hex2Int(nck)) 824 if (Rest.Hex2Int(ncl) >= Rest.Hex2Int(nck))
821 { 825 {
822 Rest.Log.WarnFormat("{0} Authentication failed: bad cnonce counter", MsgId); 826 Rest.Log.WarnFormat("{0} Authentication failed: bad cnonce counter", MsgId);
827 Fail(Rest.HttpStatusCodeBadRequest);
823 break; 828 break;
824 } 829 }
825 cntable[nonce] = nck; 830 cntable[nonce] = nck;
@@ -840,11 +845,13 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
840 if (authparms.ContainsKey("cnonce")) 845 if (authparms.ContainsKey("cnonce"))
841 { 846 {
842 Rest.Log.WarnFormat("{0} Authentication failed: invalid cnonce", MsgId); 847 Rest.Log.WarnFormat("{0} Authentication failed: invalid cnonce", MsgId);
848 Fail(Rest.HttpStatusCodeBadRequest);
843 break; 849 break;
844 } 850 }
845 if (authparms.ContainsKey("nc")) 851 if (authparms.ContainsKey("nc"))
846 { 852 {
847 Rest.Log.WarnFormat("{0} Authentication failed: invalid cnonce counter[2]", MsgId); 853 Rest.Log.WarnFormat("{0} Authentication failed: invalid cnonce counter[2]", MsgId);
854 Fail(Rest.HttpStatusCodeBadRequest);
848 break; 855 break;
849 } 856 }
850 } 857 }
@@ -857,6 +864,8 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
857 while (false); 864 while (false);
858 865
859 } 866 }
867 else
868 Fail(Rest.HttpStatusCodeBadRequest);
860 869
861 } 870 }
862 871
diff --git a/OpenSim/ApplicationPlugins/Rest/Inventory/Rest.cs b/OpenSim/ApplicationPlugins/Rest/Inventory/Rest.cs
index d7935bc..badbb08 100644
--- a/OpenSim/ApplicationPlugins/Rest/Inventory/Rest.cs
+++ b/OpenSim/ApplicationPlugins/Rest/Inventory/Rest.cs
@@ -46,6 +46,21 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
46 internal static bool DEBUG = Log.IsDebugEnabled; 46 internal static bool DEBUG = Log.IsDebugEnabled;
47 47
48 /// <summary> 48 /// <summary>
49 /// Supported authentication schemes
50 /// </summary>
51
52 public const string AS_BASIC = "Basic"; // simple user/password verification
53 public const string AS_DIGEST = "Digest"; // password safe authentication
54
55 /// Supported Digest algorithms
56
57 public const string Digest_MD5 = "MD5"; // assumed default if omitted
58 public const string Digest_MD5Sess = "MD5-sess"; // session-span - not good for REST?
59
60 public const string Qop_Auth = "auth"; // authentication only
61 public const string Qop_Int = "auth-int"; // TODO
62
63 /// <summary>
49 /// These values have a single value for the whole 64 /// These values have a single value for the whole
50 /// domain and lifetime of the plugin handler. We 65 /// domain and lifetime of the plugin handler. We
51 /// make them static for ease of reference within 66 /// make them static for ease of reference within
@@ -67,9 +82,10 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
67 internal static bool Secure = true; 82 internal static bool Secure = true;
68 internal static bool ExtendedEscape = true; 83 internal static bool ExtendedEscape = true;
69 internal static bool DumpAsset = false; 84 internal static bool DumpAsset = false;
70 internal static bool Fill = true; 85 internal static bool Fill = false;
71 internal static bool FlushEnabled = true; 86 internal static bool FlushEnabled = true;
72 internal static string Realm = "REST"; 87 internal static string Realm = "OpenSim REST";
88 internal static string Scheme = AS_BASIC;
73 internal static int DumpLineSize = 32; // Should be a multiple of 16 or (possibly) 4 89 internal static int DumpLineSize = 32; // Should be a multiple of 16 or (possibly) 4
74 90
75 /// <summary> 91 /// <summary>
@@ -383,21 +399,6 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
383 public const string HttpHeaderWarning = "Warning"; 399 public const string HttpHeaderWarning = "Warning";
384 public const string HttpHeaderWWWAuthenticate = "WWW-Authenticate"; 400 public const string HttpHeaderWWWAuthenticate = "WWW-Authenticate";
385 401
386 /// <summary>
387 /// Supported authentication schemes
388 /// </summary>
389
390 public const string AS_BASIC = "Basic";
391 public const string AS_DIGEST = "Digest";
392
393 /// Supported Digest algorithms
394
395 public const string Digest_MD5 = "MD5"; // assumed default if omitted
396 public const string Digest_MD5Sess = "MD5-sess";
397
398 public const string Qop_Auth = "auth";
399 public const string Qop_Int = "auth-int";
400
401 /// Utility routines 402 /// Utility routines
402 403
403 public static string StringToBase64(string str) 404 public static string StringToBase64(string str)
diff --git a/OpenSim/ApplicationPlugins/Rest/Inventory/RestAppearanceServices.cs b/OpenSim/ApplicationPlugins/Rest/Inventory/RestAppearanceServices.cs
index 6983154..11cda6e 100644
--- a/OpenSim/ApplicationPlugins/Rest/Inventory/RestAppearanceServices.cs
+++ b/OpenSim/ApplicationPlugins/Rest/Inventory/RestAppearanceServices.cs
@@ -63,6 +63,16 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
63 Rest.Log.InfoFormat("{0} User appearance services initializing", MsgId); 63 Rest.Log.InfoFormat("{0} User appearance services initializing", MsgId);
64 Rest.Log.InfoFormat("{0} Using REST Implementation Version {1}", MsgId, Rest.Version); 64 Rest.Log.InfoFormat("{0} Using REST Implementation Version {1}", MsgId, Rest.Version);
65 65
66 // This is better than a null reference.
67
68 if (Rest.AvatarServices == null)
69 throw new Exception(String.Format("{0} OpenSim inventory services are not available",
70 MsgId));
71
72 if (Rest.UserServices == null)
73 throw new Exception(String.Format("{0} OpenSim user profile services are not available",
74 MsgId));
75
66 // If a relative path was specified for the handler's domain, 76 // If a relative path was specified for the handler's domain,
67 // add the standard prefix to make it absolute, e.g. /admin 77 // add the standard prefix to make it absolute, e.g. /admin
68 78
@@ -170,9 +180,6 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
170 180
171 try 181 try
172 { 182 {
173 // digest scheme seems borked: disable it for the time
174 // being
175 rdata.scheme = Rest.AS_BASIC;
176 if (!rdata.IsAuthenticated) 183 if (!rdata.IsAuthenticated)
177 { 184 {
178 rdata.Fail(Rest.HttpStatusCodeNotAuthorized,String.Format("user \"{0}\" could not be authenticated", rdata.userName)); 185 rdata.Fail(Rest.HttpStatusCodeNotAuthorized,String.Format("user \"{0}\" could not be authenticated", rdata.userName));
@@ -731,7 +738,7 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
731 738
732 if (asset != UUID.Zero) 739 if (asset != UUID.Zero)
733 { 740 {
734 rdata.writer.WriteAttributeString("Item",asset.ToString()); 741 rdata.writer.WriteAttributeString("Asset",asset.ToString());
735 } 742 }
736 rdata.writer.WriteEndElement(); 743 rdata.writer.WriteEndElement();
737 } 744 }
diff --git a/OpenSim/ApplicationPlugins/Rest/Inventory/RestAssetServices.cs b/OpenSim/ApplicationPlugins/Rest/Inventory/RestAssetServices.cs
index 9af5cd0..f9abc49 100644
--- a/OpenSim/ApplicationPlugins/Rest/Inventory/RestAssetServices.cs
+++ b/OpenSim/ApplicationPlugins/Rest/Inventory/RestAssetServices.cs
@@ -52,6 +52,12 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
52 Rest.Log.InfoFormat("{0} Asset services initializing", MsgId); 52 Rest.Log.InfoFormat("{0} Asset services initializing", MsgId);
53 Rest.Log.InfoFormat("{0} Using REST Implementation Version {1}", MsgId, Rest.Version); 53 Rest.Log.InfoFormat("{0} Using REST Implementation Version {1}", MsgId, Rest.Version);
54 54
55 // This is better than a null reference.
56
57 if (Rest.AssetServices == null)
58 throw new Exception(String.Format("{0} OpenSim asset services are not available",
59 MsgId));
60
55 // If the handler specifies a relative path for its domain 61 // If the handler specifies a relative path for its domain
56 // then we must add the standard absolute prefix, e.g. /admin 62 // then we must add the standard absolute prefix, e.g. /admin
57 63
@@ -130,9 +136,6 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
130 136
131 try 137 try
132 { 138 {
133 // digest scheme seems borked: disable it for the time
134 // being
135 rdata.scheme = Rest.AS_BASIC;
136 if (!rdata.IsAuthenticated) 139 if (!rdata.IsAuthenticated)
137 { 140 {
138 rdata.Fail(Rest.HttpStatusCodeNotAuthorized, String.Format("user \"{0}\" could not be authenticated")); 141 rdata.Fail(Rest.HttpStatusCodeNotAuthorized, String.Format("user \"{0}\" could not be authenticated"));
diff --git a/OpenSim/ApplicationPlugins/Rest/Inventory/RestHandler.cs b/OpenSim/ApplicationPlugins/Rest/Inventory/RestHandler.cs
index fd4c295..c022e09 100644
--- a/OpenSim/ApplicationPlugins/Rest/Inventory/RestHandler.cs
+++ b/OpenSim/ApplicationPlugins/Rest/Inventory/RestHandler.cs
@@ -239,14 +239,17 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
239 Rest.Prefix = Prefix; 239 Rest.Prefix = Prefix;
240 Rest.GodKey = GodKey; 240 Rest.GodKey = GodKey;
241 241
242 Rest.Authenticate = Rest.Config.GetBoolean("authenticate",true); 242 Rest.Authenticate = Rest.Config.GetBoolean("authenticate", Rest.Authenticate);
243 Rest.Secure = Rest.Config.GetBoolean("secured",true); 243 Rest.Scheme = Rest.Config.GetString("auth-scheme", Rest.Scheme);
244 Rest.ExtendedEscape = Rest.Config.GetBoolean("extended-escape",true); 244 Rest.Secure = Rest.Config.GetBoolean("secured", Rest.Secure);
245 Rest.Realm = Rest.Config.GetString("realm","OpenSim REST"); 245 Rest.ExtendedEscape = Rest.Config.GetBoolean("extended-escape", Rest.ExtendedEscape);
246 Rest.DumpAsset = Rest.Config.GetBoolean("dump-asset",false); 246 Rest.Realm = Rest.Config.GetString("realm", Rest.Realm);
247 Rest.Fill = Rest.Config.GetBoolean("path-fill",true); 247 Rest.DumpAsset = Rest.Config.GetBoolean("dump-asset", Rest.DumpAsset);
248 Rest.DumpLineSize = Rest.Config.GetInt("dump-line-size",32); 248 Rest.Fill = Rest.Config.GetBoolean("path-fill", Rest.Fill);
249 Rest.FlushEnabled = Rest.Config.GetBoolean("flush-on-error",true); 249 Rest.DumpLineSize = Rest.Config.GetInt("dump-line-size", Rest.DumpLineSize);
250 Rest.FlushEnabled = Rest.Config.GetBoolean("flush-on-error", Rest.FlushEnabled);
251
252 // Note: Odd spacing is required in the following strings
250 253
251 Rest.Log.InfoFormat("{0} Authentication is {1}required", MsgId, 254 Rest.Log.InfoFormat("{0} Authentication is {1}required", MsgId,
252 (Rest.Authenticate ? "" : "not ")); 255 (Rest.Authenticate ? "" : "not "));
@@ -374,13 +377,13 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
374 377
375 string path = request.RawUrl.ToLower(); 378 string path = request.RawUrl.ToLower();
376 379
377 Rest.Log.DebugFormat("{0} Match ENTRY", MsgId); 380 // Rest.Log.DebugFormat("{0} Match ENTRY", MsgId);
378 381
379 try 382 try
380 { 383 {
381 foreach (string key in pathHandlers.Keys) 384 foreach (string key in pathHandlers.Keys)
382 { 385 {
383 Rest.Log.DebugFormat("{0} Match testing {1} against agent prefix <{2}>", MsgId, path, key); 386 // Rest.Log.DebugFormat("{0} Match testing {1} against agent prefix <{2}>", MsgId, path, key);
384 387
385 // Note that Match will not necessarily find the handler that will 388 // Note that Match will not necessarily find the handler that will
386 // actually be used - it does no test for the "closest" fit. It 389 // actually be used - it does no test for the "closest" fit. It
@@ -388,7 +391,7 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
388 391
389 if (path.StartsWith(key)) 392 if (path.StartsWith(key))
390 { 393 {
391 Rest.Log.DebugFormat("{0} Matched prefix <{1}>", MsgId, key); 394 // Rest.Log.DebugFormat("{0} Matched prefix <{1}>", MsgId, key);
392 395
393 // This apparently odd evaluation is needed to prevent a match 396 // This apparently odd evaluation is needed to prevent a match
394 // on anything other than a URI token boundary. Otherwise we 397 // on anything other than a URI token boundary. Otherwise we
@@ -404,7 +407,7 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
404 407
405 foreach (string key in streamHandlers.Keys) 408 foreach (string key in streamHandlers.Keys)
406 { 409 {
407 Rest.Log.DebugFormat("{0} Match testing {1} against stream prefix <{2}>", MsgId, path, key); 410 // Rest.Log.DebugFormat("{0} Match testing {1} against stream prefix <{2}>", MsgId, path, key);
408 411
409 // Note that Match will not necessarily find the handler that will 412 // Note that Match will not necessarily find the handler that will
410 // actually be used - it does no test for the "closest" fit. It 413 // actually be used - it does no test for the "closest" fit. It
@@ -412,7 +415,7 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
412 415
413 if (path.StartsWith(key)) 416 if (path.StartsWith(key))
414 { 417 {
415 Rest.Log.DebugFormat("{0} Matched prefix <{1}>", MsgId, key); 418 // Rest.Log.DebugFormat("{0} Matched prefix <{1}>", MsgId, key);
416 419
417 // This apparently odd evaluation is needed to prevent a match 420 // This apparently odd evaluation is needed to prevent a match
418 // on anything other than a URI token boundary. Otherwise we 421 // on anything other than a URI token boundary. Otherwise we
@@ -434,7 +437,7 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
434 437
435 /// <summary> 438 /// <summary>
436 /// This is called by the HTTP server once the handler has indicated 439 /// This is called by the HTTP server once the handler has indicated
437 /// that t is able to handle the request. 440 /// that it is able to handle the request.
438 /// Preconditions: 441 /// Preconditions:
439 /// [1] request != null and is a valid request object 442 /// [1] request != null and is a valid request object
440 /// [2] response != null and is a valid response object 443 /// [2] response != null and is a valid response object
@@ -474,7 +477,11 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
474 { 477 {
475 // A raw exception indicates that something we weren't expecting has 478 // A raw exception indicates that something we weren't expecting has
476 // happened. This should always reflect a shortcoming in the plugin, 479 // happened. This should always reflect a shortcoming in the plugin,
477 // or a failure to satisfy the preconditions. 480 // or a failure to satisfy the preconditions. It should not reflect
481 // an error in the request itself. Under such circumstances the state
482 // of the request cannot be determined and we are obliged to mark it
483 // as 'handled'.
484
478 Rest.Log.ErrorFormat("{0} Plugin error: {1}", MsgId, e.Message); 485 Rest.Log.ErrorFormat("{0} Plugin error: {1}", MsgId, e.Message);
479 handled = true; 486 handled = true;
480 } 487 }
@@ -497,7 +504,7 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
497 { 504 {
498 RequestData rdata = new RequestData(request, response, String.Empty); 505 RequestData rdata = new RequestData(request, response, String.Empty);
499 506
500 string bestMatch = null; 507 string bestMatch = String.Empty;
501 string path = String.Format("{0}:{1}", rdata.method, rdata.path).ToLower(); 508 string path = String.Format("{0}:{1}", rdata.method, rdata.path).ToLower();
502 509
503 Rest.Log.DebugFormat("{0} Checking for stream handler for <{1}>", MsgId, path); 510 Rest.Log.DebugFormat("{0} Checking for stream handler for <{1}>", MsgId, path);
@@ -511,7 +518,7 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
511 { 518 {
512 if (path.StartsWith(pattern)) 519 if (path.StartsWith(pattern))
513 { 520 {
514 if (String.IsNullOrEmpty(bestMatch) || pattern.Length > bestMatch.Length) 521 if (pattern.Length > bestMatch.Length)
515 { 522 {
516 bestMatch = pattern; 523 bestMatch = pattern;
517 } 524 }
@@ -520,7 +527,7 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
520 527
521 // Handle using the best match available 528 // Handle using the best match available
522 529
523 if (!String.IsNullOrEmpty(bestMatch)) 530 if (bestMatch.Length > 0)
524 { 531 {
525 Rest.Log.DebugFormat("{0} Stream-based handler matched with <{1}>", MsgId, bestMatch); 532 Rest.Log.DebugFormat("{0} Stream-based handler matched with <{1}>", MsgId, bestMatch);
526 RestStreamHandler handler = streamHandlers[bestMatch]; 533 RestStreamHandler handler = streamHandlers[bestMatch];
diff --git a/OpenSim/ApplicationPlugins/Rest/Inventory/RestInventoryServices.cs b/OpenSim/ApplicationPlugins/Rest/Inventory/RestInventoryServices.cs
index 9cbbf0c..003c6ee 100644
--- a/OpenSim/ApplicationPlugins/Rest/Inventory/RestInventoryServices.cs
+++ b/OpenSim/ApplicationPlugins/Rest/Inventory/RestInventoryServices.cs
@@ -31,6 +31,7 @@ using System.IO;
31using System.Threading; 31using System.Threading;
32using System.Xml; 32using System.Xml;
33using System.Drawing; 33using System.Drawing;
34using System.Timers;
34using OpenSim.Framework; 35using OpenSim.Framework;
35using OpenSim.Framework.Servers; 36using OpenSim.Framework.Servers;
36using OpenSim.Framework.Communications; 37using OpenSim.Framework.Communications;
@@ -61,6 +62,20 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
61 Rest.Log.InfoFormat("{0} Inventory services initializing", MsgId); 62 Rest.Log.InfoFormat("{0} Inventory services initializing", MsgId);
62 Rest.Log.InfoFormat("{0} Using REST Implementation Version {1}", MsgId, Rest.Version); 63 Rest.Log.InfoFormat("{0} Using REST Implementation Version {1}", MsgId, Rest.Version);
63 64
65 // This is better than a null reference.
66
67 if (Rest.InventoryServices == null)
68 throw new Exception(String.Format("{0} OpenSim inventory services are not available",
69 MsgId));
70
71 if (Rest.UserServices == null)
72 throw new Exception(String.Format("{0} OpenSim user services are not available",
73 MsgId));
74
75 if (Rest.AssetServices == null)
76 throw new Exception(String.Format("{0} OpenSim asset services are not available",
77 MsgId));
78
64 // If a relative path was specified for the handler's domain, 79 // If a relative path was specified for the handler's domain,
65 // add the standard prefix to make it absolute, e.g. /admin 80 // add the standard prefix to make it absolute, e.g. /admin
66 81
@@ -167,9 +182,6 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
167 182
168 try 183 try
169 { 184 {
170 // digest scheme seems borked: disable it for the time
171 // being
172 rdata.scheme = Rest.AS_BASIC;
173 if (!rdata.IsAuthenticated) 185 if (!rdata.IsAuthenticated)
174 { 186 {
175 rdata.Fail(Rest.HttpStatusCodeNotAuthorized,String.Format("user \"{0}\" could not be authenticated", rdata.userName)); 187 rdata.Fail(Rest.HttpStatusCodeNotAuthorized,String.Format("user \"{0}\" could not be authenticated", rdata.userName));
@@ -283,12 +295,22 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
283 Rest.Log.DebugFormat("{0} Inventory catalog requested for {1} {2}", 295 Rest.Log.DebugFormat("{0} Inventory catalog requested for {1} {2}",
284 MsgId, rdata.userProfile.FirstName, rdata.userProfile.SurName); 296 MsgId, rdata.userProfile.FirstName, rdata.userProfile.SurName);
285 297
286 lock (rdata) 298
299 lock (rdata)
300 {
301 if (!rdata.HaveInventory)
302 {
303 rdata.startWD(1000);
304 rdata.timeout = false;
305 Monitor.Wait(rdata);
306 }
307 }
308
309 if (rdata.timeout)
287 { 310 {
288 if (!rdata.HaveInventory) 311 Rest.Log.WarnFormat("{0} Inventory not available for {1} {2}. No response from service.",
289 { 312 MsgId, rdata.userProfile.FirstName, rdata.userProfile.SurName);
290 Monitor.Wait(rdata); 313 rdata.Fail(Rest.HttpStatusCodeServerError, "inventory server not responding");
291 }
292 } 314 }
293 315
294 if (rdata.root == null) 316 if (rdata.root == null)
@@ -2145,12 +2167,50 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
2145 internal ICollection<InventoryItemBase> items = null; 2167 internal ICollection<InventoryItemBase> items = null;
2146 internal UserProfileData userProfile = null; 2168 internal UserProfileData userProfile = null;
2147 internal InventoryFolderBase root = null; 2169 internal InventoryFolderBase root = null;
2170 internal bool timeout = false;
2171 internal System.Timers.Timer watchDog = new System.Timers.Timer();
2148 2172
2149 internal InventoryRequestData(OSHttpRequest request, OSHttpResponse response, string prefix) 2173 internal InventoryRequestData(OSHttpRequest request, OSHttpResponse response, string prefix)
2150 : base(request, response, prefix) 2174 : base(request, response, prefix)
2151 { 2175 {
2152 } 2176 }
2153 2177
2178 internal void startWD(double interval)
2179 {
2180 Rest.Log.DebugFormat("{0} Setting watchdog", MsgId);
2181 watchDog.Elapsed += new ElapsedEventHandler(OnTimeOut);
2182 watchDog.Interval = interval;
2183 watchDog.AutoReset = false;
2184 watchDog.Enabled = true;
2185 watchDog.Start();
2186 }
2187
2188 internal void stopWD()
2189 {
2190 Rest.Log.DebugFormat("{0} Reset watchdog", MsgId);
2191 watchDog.Stop();
2192 }
2193
2194 /// <summary>
2195 /// This is the callback method required by the inventory watchdog. The
2196 /// requestor issues an inventory request and then blocks until the
2197 /// request completes, or this method signals the monitor.
2198 /// </summary>
2199
2200 private void OnTimeOut(object sender, ElapsedEventArgs args)
2201 {
2202 Rest.Log.DebugFormat("{0} Asynchronous inventory update timed-out", MsgId);
2203 // InventoryRequestData rdata = (InventoryRequestData) sender;
2204 lock (this)
2205 {
2206 this.folders = null;
2207 this.items = null;
2208 this.HaveInventory = false;
2209 this.timeout = true;
2210 Monitor.Pulse(this);
2211 }
2212 }
2213
2154 /// <summary> 2214 /// <summary>
2155 /// This is the callback method required by inventory services. The 2215 /// This is the callback method required by inventory services. The
2156 /// requestor issues an inventory request and then blocks until this 2216 /// requestor issues an inventory request and then blocks until this
@@ -2160,11 +2220,16 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
2160 internal void GetUserInventory(ICollection<InventoryFolderImpl> folders, ICollection<InventoryItemBase> items) 2220 internal void GetUserInventory(ICollection<InventoryFolderImpl> folders, ICollection<InventoryItemBase> items)
2161 { 2221 {
2162 Rest.Log.DebugFormat("{0} Asynchronously updating inventory data", MsgId); 2222 Rest.Log.DebugFormat("{0} Asynchronously updating inventory data", MsgId);
2163 this.folders = folders;
2164 this.items = items;
2165 this.HaveInventory = true;
2166 lock (this) 2223 lock (this)
2167 { 2224 {
2225 if (watchDog.Enabled)
2226 {
2227 this.stopWD();
2228 }
2229 this.folders = folders;
2230 this.items = items;
2231 this.HaveInventory = true;
2232 this.timeout = false;
2168 Monitor.Pulse(this); 2233 Monitor.Pulse(this);
2169 } 2234 }
2170 } 2235 }
diff --git a/OpenSim/Framework/Communications/Cache/LibraryRootFolder.cs b/OpenSim/Framework/Communications/Cache/LibraryRootFolder.cs
index a33fa67..437e5e4 100644
--- a/OpenSim/Framework/Communications/Cache/LibraryRootFolder.cs
+++ b/OpenSim/Framework/Communications/Cache/LibraryRootFolder.cs
@@ -178,8 +178,14 @@ namespace OpenSim.Framework.Communications.Cache
178 if (libraryFolders.ContainsKey(item.Folder)) 178 if (libraryFolders.ContainsKey(item.Folder))
179 { 179 {
180 InventoryFolderImpl parentFolder = libraryFolders[item.Folder]; 180 InventoryFolderImpl parentFolder = libraryFolders[item.Folder];
181 181 try
182 parentFolder.Items.Add(item.ID, item); 182 {
183 parentFolder.Items.Add(item.ID, item);
184 }
185 catch (Exception)
186 {
187 m_log.WarnFormat("[LIBRARY INVENTORY] Item {1} [{0}] not added, duplicate item", item.ID, item.Name);
188 }
183 } 189 }
184 else 190 else
185 { 191 {