aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Capabilities
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Capabilities')
-rw-r--r--OpenSim/Capabilities/Caps.cs29
-rw-r--r--OpenSim/Capabilities/CapsHandlers.cs35
-rw-r--r--OpenSim/Capabilities/Handlers/AvatarPickerSearch/AvatarPickerSearchHandler.cs2
-rw-r--r--OpenSim/Capabilities/Handlers/FetchInventory/FetchInvDescHandler.cs46
-rw-r--r--OpenSim/Capabilities/Handlers/FetchInventory/FetchInventory2Handler.cs33
-rw-r--r--OpenSim/Capabilities/Handlers/FetchInventory/FetchInventory2ServerConnector.cs71
-rw-r--r--OpenSim/Capabilities/Handlers/FetchInventory/Tests/FetchInventory2HandlerTests.cs2
-rw-r--r--OpenSim/Capabilities/Handlers/FetchInventory/Tests/FetchInventoryDescendents2HandlerTests.cs7
-rw-r--r--OpenSim/Capabilities/Handlers/GetDisplayNames/GetDisplayNamesHandler.cs61
-rw-r--r--OpenSim/Capabilities/Handlers/GetDisplayNames/GetDisplayNamesServerConnector.cs2
-rw-r--r--OpenSim/Capabilities/Handlers/GetMesh/GetMeshHandler.cs332
-rw-r--r--OpenSim/Capabilities/Handlers/GetMesh/GetMeshServerConnector.cs16
-rw-r--r--OpenSim/Capabilities/Handlers/GetTexture/GetTextureHandler.cs267
-rw-r--r--OpenSim/Capabilities/Handlers/GetTexture/GetTextureRobustHandler.cs394
-rw-r--r--OpenSim/Capabilities/Handlers/GetTexture/GetTextureServerConnector.cs6
-rw-r--r--OpenSim/Capabilities/Handlers/GetTexture/Tests/GetTextureHandlerTests.cs4
-rw-r--r--OpenSim/Capabilities/Handlers/Properties/AssemblyInfo.cs10
-rw-r--r--OpenSim/Capabilities/Handlers/UploadBakedTexture/UploadBakedTextureHandler.cs26
-rw-r--r--OpenSim/Capabilities/Handlers/UploadBakedTexture/UploadBakedTextureServerConnector.cs2
-rw-r--r--OpenSim/Capabilities/LLSD.cs4
-rw-r--r--OpenSim/Capabilities/LLSDAssetUploadComplete.cs7
-rw-r--r--OpenSim/Capabilities/LLSDAssetUploadRequest.cs15
-rw-r--r--OpenSim/Capabilities/LLSDAssetUploadResponse.cs35
-rw-r--r--OpenSim/Capabilities/LLSDAvatarPicker.cs2
-rw-r--r--OpenSim/Capabilities/LLSDHelpers.cs5
-rw-r--r--OpenSim/Capabilities/LLSDInventoryItem.cs6
-rw-r--r--OpenSim/Capabilities/LLSDStreamHandler.cs3
-rw-r--r--OpenSim/Capabilities/Properties/AssemblyInfo.cs8
28 files changed, 982 insertions, 448 deletions
diff --git a/OpenSim/Capabilities/Caps.cs b/OpenSim/Capabilities/Caps.cs
index 049afab..7492602 100644
--- a/OpenSim/Capabilities/Caps.cs
+++ b/OpenSim/Capabilities/Caps.cs
@@ -30,6 +30,7 @@ using System.Collections;
30using System.Collections.Generic; 30using System.Collections.Generic;
31using System.IO; 31using System.IO;
32using System.Reflection; 32using System.Reflection;
33using System.Threading;
33using log4net; 34using log4net;
34using Nini.Config; 35using Nini.Config;
35using OpenMetaverse; 36using OpenMetaverse;
@@ -63,7 +64,7 @@ namespace OpenSim.Framework.Capabilities
63 64
64 private CapsHandlers m_capsHandlers; 65 private CapsHandlers m_capsHandlers;
65 66
66 private Dictionary<string, PollServiceEventArgs> m_pollServiceHandlers 67 private Dictionary<string, PollServiceEventArgs> m_pollServiceHandlers
67 = new Dictionary<string, PollServiceEventArgs>(); 68 = new Dictionary<string, PollServiceEventArgs>();
68 69
69 private Dictionary<string, string> m_externalCapsHandlers = new Dictionary<string, string>(); 70 private Dictionary<string, string> m_externalCapsHandlers = new Dictionary<string, string>();
@@ -71,6 +72,7 @@ namespace OpenSim.Framework.Capabilities
71 private IHttpServer m_httpListener; 72 private IHttpServer m_httpListener;
72 private UUID m_agentID; 73 private UUID m_agentID;
73 private string m_regionName; 74 private string m_regionName;
75 private ManualResetEvent m_capsActive = new ManualResetEvent(false);
74 76
75 public UUID AgentID 77 public UUID AgentID
76 { 78 {
@@ -134,8 +136,14 @@ namespace OpenSim.Framework.Capabilities
134 } 136 }
135 137
136 m_agentID = agent; 138 m_agentID = agent;
137 m_capsHandlers = new CapsHandlers(httpServer, httpListen, httpPort, (httpServer == null) ? false : httpServer.UseSSL); 139 m_capsHandlers = new CapsHandlers(httpServer, httpListen, httpPort);
138 m_regionName = regionName; 140 m_regionName = regionName;
141 m_capsActive.Reset();
142 }
143
144 ~Caps()
145 {
146 m_capsActive.Dispose();
139 } 147 }
140 148
141 /// <summary> 149 /// <summary>
@@ -152,7 +160,7 @@ namespace OpenSim.Framework.Capabilities
152 public void RegisterPollHandler(string capName, PollServiceEventArgs pollServiceHandler) 160 public void RegisterPollHandler(string capName, PollServiceEventArgs pollServiceHandler)
153 { 161 {
154// m_log.DebugFormat( 162// m_log.DebugFormat(
155// "[CAPS]: Registering handler with name {0}, url {1} for {2}", 163// "[CAPS]: Registering handler with name {0}, url {1} for {2}",
156// capName, pollServiceHandler.Url, m_agentID, m_regionName); 164// capName, pollServiceHandler.Url, m_agentID, m_regionName);
157 165
158 m_pollServiceHandlers.Add(capName, pollServiceHandler); 166 m_pollServiceHandlers.Add(capName, pollServiceHandler);
@@ -162,7 +170,7 @@ namespace OpenSim.Framework.Capabilities
162// uint port = (MainServer.Instance == null) ? 0 : MainServer.Instance.Port; 170// uint port = (MainServer.Instance == null) ? 0 : MainServer.Instance.Port;
163// string protocol = "http"; 171// string protocol = "http";
164// string hostName = m_httpListenerHostName; 172// string hostName = m_httpListenerHostName;
165// 173//
166// if (MainServer.Instance.UseSSL) 174// if (MainServer.Instance.UseSSL)
167// { 175// {
168// hostName = MainServer.Instance.SSLCommonName; 176// hostName = MainServer.Instance.SSLCommonName;
@@ -230,7 +238,7 @@ namespace OpenSim.Framework.Capabilities
230 string hostName = m_httpListenerHostName; 238 string hostName = m_httpListenerHostName;
231 uint port = (MainServer.Instance == null) ? 0 : MainServer.Instance.Port; 239 uint port = (MainServer.Instance == null) ? 0 : MainServer.Instance.Port;
232 string protocol = "http"; 240 string protocol = "http";
233 241
234 if (MainServer.Instance.UseSSL) 242 if (MainServer.Instance.UseSSL)
235 { 243 {
236 hostName = MainServer.Instance.SSLCommonName; 244 hostName = MainServer.Instance.SSLCommonName;
@@ -255,5 +263,16 @@ namespace OpenSim.Framework.Capabilities
255 263
256 return caps; 264 return caps;
257 } 265 }
266
267 public void Activate()
268 {
269 m_capsActive.Set();
270 }
271
272 public bool WaitForActivation()
273 {
274 // Wait for 30s. If that elapses, return false and run without caps
275 return m_capsActive.WaitOne(120000);
276 }
258 } 277 }
259} \ No newline at end of file 278} \ No newline at end of file
diff --git a/OpenSim/Capabilities/CapsHandlers.cs b/OpenSim/Capabilities/CapsHandlers.cs
index 890df90..f5a40df 100644
--- a/OpenSim/Capabilities/CapsHandlers.cs
+++ b/OpenSim/Capabilities/CapsHandlers.cs
@@ -53,31 +53,15 @@ namespace OpenSim.Framework.Capabilities
53 /// <param name="httpListener">base HTTP server</param> 53 /// <param name="httpListener">base HTTP server</param>
54 /// <param name="httpListenerHostname">host name of the HTTP server</param> 54 /// <param name="httpListenerHostname">host name of the HTTP server</param>
55 /// <param name="httpListenerPort">HTTP port</param> 55 /// <param name="httpListenerPort">HTTP port</param>
56 public CapsHandlers(BaseHttpServer httpListener, string httpListenerHostname, uint httpListenerPort) 56 public CapsHandlers(IHttpServer httpListener, string httpListenerHostname, uint httpListenerPort)
57 : this(httpListener,httpListenerHostname,httpListenerPort, false) 57 {
58 {
59 }
60
61 /// <summary></summary>
62 /// CapsHandlers is a cap handler container but also takes
63 /// care of adding and removing cap handlers to and from the
64 /// supplied BaseHttpServer.
65 /// </summary>
66 /// <param name="httpListener">base HTTP server</param>
67 /// <param name="httpListenerHostname">host name of the HTTP
68 /// server</param>
69 /// <param name="httpListenerPort">HTTP port</param>
70 public CapsHandlers(IHttpServer httpListener, string httpListenerHostname, uint httpListenerPort, bool https)
71 {
72 m_httpListener = httpListener; 58 m_httpListener = httpListener;
73 m_httpListenerHostName = httpListenerHostname; 59 m_httpListenerHostName = httpListenerHostname;
74 m_httpListenerPort = httpListenerPort; 60 m_httpListenerPort = httpListenerPort;
75 m_useSSL = https; 61 if (httpListener != null && httpListener.UseSSL)
76 if (httpListener != null && m_useSSL) 62 m_useSSL = true;
77 { 63 else
78 m_httpListenerHostName = httpListener.SSLCommonName; 64 m_useSSL = false;
79 m_httpListenerPort = httpListener.SSLPort;
80 }
81 } 65 }
82 66
83 /// <summary> 67 /// <summary>
@@ -90,6 +74,7 @@ namespace OpenSim.Framework.Capabilities
90 lock (m_capsHandlers) 74 lock (m_capsHandlers)
91 { 75 {
92 m_httpListener.RemoveStreamHandler("POST", m_capsHandlers[capsName].Path); 76 m_httpListener.RemoveStreamHandler("POST", m_capsHandlers[capsName].Path);
77 m_httpListener.RemoveStreamHandler("PUT", m_capsHandlers[capsName].Path);
93 m_httpListener.RemoveStreamHandler("GET", m_capsHandlers[capsName].Path); 78 m_httpListener.RemoveStreamHandler("GET", m_capsHandlers[capsName].Path);
94 m_capsHandlers.Remove(capsName); 79 m_capsHandlers.Remove(capsName);
95 } 80 }
@@ -127,9 +112,9 @@ namespace OpenSim.Framework.Capabilities
127 m_httpListener.RemoveStreamHandler("POST", m_capsHandlers[idx].Path); 112 m_httpListener.RemoveStreamHandler("POST", m_capsHandlers[idx].Path);
128 m_capsHandlers.Remove(idx); 113 m_capsHandlers.Remove(idx);
129 } 114 }
130 115
131 if (null == value) return; 116 if (null == value) return;
132 117
133 m_capsHandlers[idx] = value; 118 m_capsHandlers[idx] = value;
134 m_httpListener.AddStreamHandler(value); 119 m_httpListener.AddStreamHandler(value);
135 } 120 }
@@ -162,7 +147,7 @@ namespace OpenSim.Framework.Capabilities
162 { 147 {
163 Hashtable caps = new Hashtable(); 148 Hashtable caps = new Hashtable();
164 string protocol = "http://"; 149 string protocol = "http://";
165 150
166 if (m_useSSL) 151 if (m_useSSL)
167 protocol = "https://"; 152 protocol = "https://";
168 153
diff --git a/OpenSim/Capabilities/Handlers/AvatarPickerSearch/AvatarPickerSearchHandler.cs b/OpenSim/Capabilities/Handlers/AvatarPickerSearch/AvatarPickerSearchHandler.cs
index 426174d..5163169 100644
--- a/OpenSim/Capabilities/Handlers/AvatarPickerSearch/AvatarPickerSearchHandler.cs
+++ b/OpenSim/Capabilities/Handlers/AvatarPickerSearch/AvatarPickerSearchHandler.cs
@@ -74,7 +74,7 @@ namespace OpenSim.Capabilities.Handlers
74 74
75 int page_size = (string.IsNullOrEmpty(psize) ? 500 : Int32.Parse(psize)); 75 int page_size = (string.IsNullOrEmpty(psize) ? 500 : Int32.Parse(psize));
76 int page_number = (string.IsNullOrEmpty(pnumber) ? 1 : Int32.Parse(pnumber)); 76 int page_number = (string.IsNullOrEmpty(pnumber) ? 1 : Int32.Parse(pnumber));
77 77
78 // Full content request 78 // Full content request
79 httpResponse.StatusCode = (int)System.Net.HttpStatusCode.OK; 79 httpResponse.StatusCode = (int)System.Net.HttpStatusCode.OK;
80 //httpResponse.ContentLength = ??; 80 //httpResponse.ContentLength = ??;
diff --git a/OpenSim/Capabilities/Handlers/FetchInventory/FetchInvDescHandler.cs b/OpenSim/Capabilities/Handlers/FetchInventory/FetchInvDescHandler.cs
index 7197049..53ed115 100644
--- a/OpenSim/Capabilities/Handlers/FetchInventory/FetchInvDescHandler.cs
+++ b/OpenSim/Capabilities/Handlers/FetchInventory/FetchInvDescHandler.cs
@@ -43,7 +43,7 @@ using Caps = OpenSim.Framework.Capabilities.Caps;
43 43
44namespace OpenSim.Capabilities.Handlers 44namespace OpenSim.Capabilities.Handlers
45{ 45{
46 public class FetchInvDescHandler 46 public class FetchInvDescHandler
47 { 47 {
48 private static readonly ILog m_log = 48 private static readonly ILog m_log =
49 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 49 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
@@ -53,14 +53,14 @@ namespace OpenSim.Capabilities.Handlers
53 private IScene m_Scene; 53 private IScene m_Scene;
54// private object m_fetchLock = new Object(); 54// private object m_fetchLock = new Object();
55 55
56 public FetchInvDescHandler(IInventoryService invService, ILibraryService libService, IScene s) 56 public FetchInvDescHandler(IInventoryService invService, ILibraryService libService, IScene s)
57 { 57 {
58 m_InventoryService = invService; 58 m_InventoryService = invService;
59 m_LibraryService = libService; 59 m_LibraryService = libService;
60 m_Scene = s; 60 m_Scene = s;
61 } 61 }
62 62
63 63
64 public string FetchInventoryDescendentsRequest(string request, string path, string param, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) 64 public string FetchInventoryDescendentsRequest(string request, string path, string param, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
65 { 65 {
66 //m_log.DebugFormat("[XXX]: FetchInventoryDescendentsRequest in {0}, {1}", (m_Scene == null) ? "none" : m_Scene.Name, request); 66 //m_log.DebugFormat("[XXX]: FetchInventoryDescendentsRequest in {0}, {1}", (m_Scene == null) ? "none" : m_Scene.Name, request);
@@ -72,14 +72,14 @@ namespace OpenSim.Capabilities.Handlers
72 // correctly mark it as a uuid 72 // correctly mark it as a uuid
73 // 73 //
74 request = request.Replace("<string>00000000-0000-0000-0000-000000000000</string>", "<uuid>00000000-0000-0000-0000-000000000000</uuid>"); 74 request = request.Replace("<string>00000000-0000-0000-0000-000000000000</string>", "<uuid>00000000-0000-0000-0000-000000000000</uuid>");
75 75
76 // another hack <integer>1</integer> results in a 76 // another hack <integer>1</integer> results in a
77 // System.ArgumentException: Object type System.Int32 cannot 77 // System.ArgumentException: Object type System.Int32 cannot
78 // be converted to target type: System.Boolean 78 // be converted to target type: System.Boolean
79 // 79 //
80 request = request.Replace("<key>fetch_folders</key><integer>0</integer>", "<key>fetch_folders</key><boolean>0</boolean>"); 80 request = request.Replace("<key>fetch_folders</key><integer>0</integer>", "<key>fetch_folders</key><boolean>0</boolean>");
81 request = request.Replace("<key>fetch_folders</key><integer>1</integer>", "<key>fetch_folders</key><boolean>1</boolean>"); 81 request = request.Replace("<key>fetch_folders</key><integer>1</integer>", "<key>fetch_folders</key><boolean>1</boolean>");
82 82
83 Hashtable hash = new Hashtable(); 83 Hashtable hash = new Hashtable();
84 try 84 try
85 { 85 {
@@ -90,9 +90,9 @@ namespace OpenSim.Capabilities.Handlers
90 m_log.ErrorFormat("[WEB FETCH INV DESC HANDLER]: Fetch error: {0}{1}" + e.Message, e.StackTrace); 90 m_log.ErrorFormat("[WEB FETCH INV DESC HANDLER]: Fetch error: {0}{1}" + e.Message, e.StackTrace);
91 m_log.Error("Request: " + request); 91 m_log.Error("Request: " + request);
92 } 92 }
93 93
94 ArrayList foldersrequested = (ArrayList)hash["folders"]; 94 ArrayList foldersrequested = (ArrayList)hash["folders"];
95 95
96 string response = ""; 96 string response = "";
97 string bad_folders_response = ""; 97 string bad_folders_response = "";
98 98
@@ -403,10 +403,7 @@ namespace OpenSim.Capabilities.Handlers
403 return contents; 403 return contents;
404 } 404 }
405 contents = fetchedContents; 405 contents = fetchedContents;
406 InventoryFolderBase containingFolder = new InventoryFolderBase(); 406 InventoryFolderBase containingFolder = m_InventoryService.GetFolder(agentID, folderID);
407 containingFolder.ID = folderID;
408 containingFolder.Owner = agentID;
409 containingFolder = m_InventoryService.GetFolder(containingFolder);
410 407
411 if (containingFolder != null) 408 if (containingFolder != null)
412 { 409 {
@@ -416,7 +413,7 @@ namespace OpenSim.Capabilities.Handlers
416 413
417 version = containingFolder.Version; 414 version = containingFolder.Version;
418 415
419 if (fetchItems) 416 if (fetchItems && containingFolder.Type != (short)FolderType.Trash)
420 { 417 {
421 List<InventoryItemBase> itemsToReturn = contents.Items; 418 List<InventoryItemBase> itemsToReturn = contents.Items;
422 List<InventoryItemBase> originalItems = new List<InventoryItemBase>(itemsToReturn); 419 List<InventoryItemBase> originalItems = new List<InventoryItemBase>(itemsToReturn);
@@ -429,7 +426,7 @@ namespace OpenSim.Capabilities.Handlers
429 { 426 {
430 if (item.AssetType == (int)AssetType.Link) 427 if (item.AssetType == (int)AssetType.Link)
431 { 428 {
432 InventoryItemBase linkedItem = m_InventoryService.GetItem(new InventoryItemBase(item.AssetID)); 429 InventoryItemBase linkedItem = m_InventoryService.GetItem(agentID, item.AssetID);
433 430
434 // Take care of genuinely broken links where the target doesn't exist 431 // Take care of genuinely broken links where the target doesn't exist
435 // HACK: Also, don't follow up links that just point to other links. In theory this is legitimate, 432 // HACK: Also, don't follow up links that just point to other links. In theory this is legitimate,
@@ -441,6 +438,10 @@ namespace OpenSim.Capabilities.Handlers
441 } 438 }
442 439
443 // Now scan for folder links and insert the items they target and those links at the head of the return data 440 // Now scan for folder links and insert the items they target and those links at the head of the return data
441
442/* dont send contents of LinkFolders.
443from docs seems this was never a spec
444
444 foreach (InventoryItemBase item in originalItems) 445 foreach (InventoryItemBase item in originalItems)
445 { 446 {
446 if (item.AssetType == (int)AssetType.LinkFolder) 447 if (item.AssetType == (int)AssetType.LinkFolder)
@@ -471,6 +472,7 @@ namespace OpenSim.Capabilities.Handlers
471 } 472 }
472 } 473 }
473 } 474 }
475*/
474 } 476 }
475 477
476// foreach (InventoryItemBase item in contents.Items) 478// foreach (InventoryItemBase item in contents.Items)
@@ -514,7 +516,7 @@ namespace OpenSim.Capabilities.Handlers
514// } 516// }
515// } 517// }
516// } 518// }
517// 519//
518// foreach (UUID linkedItemFolderId in linkedItemFolderIdsToSend) 520// foreach (UUID linkedItemFolderId in linkedItemFolderIdsToSend)
519// { 521// {
520// m_log.DebugFormat( 522// m_log.DebugFormat(
@@ -654,10 +656,7 @@ namespace OpenSim.Capabilities.Handlers
654 // Must fetch it individually 656 // Must fetch it individually
655 else if (contents.FolderID == UUID.Zero) 657 else if (contents.FolderID == UUID.Zero)
656 { 658 {
657 InventoryFolderBase containingFolder = new InventoryFolderBase(); 659 InventoryFolderBase containingFolder = m_InventoryService.GetFolder(freq.owner_id, freq.folder_id);
658 containingFolder.ID = freq.folder_id;
659 containingFolder.Owner = freq.owner_id;
660 containingFolder = m_InventoryService.GetFolder(containingFolder);
661 660
662 if (containingFolder != null) 661 if (containingFolder != null)
663 { 662 {
@@ -723,8 +722,8 @@ namespace OpenSim.Capabilities.Handlers
723 if (item.AssetType == (int)AssetType.Link) 722 if (item.AssetType == (int)AssetType.Link)
724 itemIDs.Add(item.AssetID); 723 itemIDs.Add(item.AssetID);
725 724
726 else if (item.AssetType == (int)AssetType.LinkFolder) 725// else if (item.AssetType == (int)AssetType.LinkFolder)
727 folderIDs.Add(item.AssetID); 726// folderIDs.Add(item.AssetID);
728 } 727 }
729 728
730 //m_log.DebugFormat("[XXX]: folder {0} has {1} links and {2} linkfolders", contents.FolderID, itemIDs.Count, folderIDs.Count); 729 //m_log.DebugFormat("[XXX]: folder {0} has {1} links and {2} linkfolders", contents.FolderID, itemIDs.Count, folderIDs.Count);
@@ -754,12 +753,9 @@ namespace OpenSim.Capabilities.Handlers
754 m_log.WarnFormat("[WEB FETCH INV DESC HANDLER]: GetMultipleItems failed. Falling back to fetching inventory items one by one."); 753 m_log.WarnFormat("[WEB FETCH INV DESC HANDLER]: GetMultipleItems failed. Falling back to fetching inventory items one by one.");
755 linked = new InventoryItemBase[itemIDs.Count]; 754 linked = new InventoryItemBase[itemIDs.Count];
756 int i = 0; 755 int i = 0;
757 InventoryItemBase item = new InventoryItemBase();
758 item.Owner = freq.owner_id;
759 foreach (UUID id in itemIDs) 756 foreach (UUID id in itemIDs)
760 { 757 {
761 item.ID = id; 758 linked[i++] = m_InventoryService.GetItem(freq.owner_id, id);
762 linked[i++] = m_InventoryService.GetItem(item);
763 } 759 }
764 } 760 }
765 761
@@ -845,4 +841,4 @@ namespace OpenSim.Capabilities.Handlers
845 public InventoryCollection Collection; 841 public InventoryCollection Collection;
846 public int Descendents; 842 public int Descendents;
847 } 843 }
848} \ No newline at end of file 844}
diff --git a/OpenSim/Capabilities/Handlers/FetchInventory/FetchInventory2Handler.cs b/OpenSim/Capabilities/Handlers/FetchInventory/FetchInventory2Handler.cs
index c904392..e239a90 100644
--- a/OpenSim/Capabilities/Handlers/FetchInventory/FetchInventory2Handler.cs
+++ b/OpenSim/Capabilities/Handlers/FetchInventory/FetchInventory2Handler.cs
@@ -64,27 +64,33 @@ namespace OpenSim.Capabilities.Handlers
64 64
65 UUID[] itemIDs = new UUID[itemsRequested.Count]; 65 UUID[] itemIDs = new UUID[itemsRequested.Count];
66 int i = 0; 66 int i = 0;
67
67 foreach (OSDMap osdItemId in itemsRequested) 68 foreach (OSDMap osdItemId in itemsRequested)
68 { 69 {
69 itemIDs[i++] = osdItemId["item_id"].AsUUID(); 70 itemIDs[i++] = osdItemId["item_id"].AsUUID();
70 } 71 }
71 72
72 InventoryItemBase[] items = m_inventoryService.GetMultipleItems(m_agentID, itemIDs); 73 InventoryItemBase[] items = null;
73 74
74 if (items == null) 75 if (m_agentID != UUID.Zero)
75 { 76 {
76 // OMG!!! One by one!!! This is fallback code, in case the backend isn't updated 77 items = m_inventoryService.GetMultipleItems(m_agentID, itemIDs);
77 m_log.WarnFormat("[FETCH INVENTORY HANDLER]: GetMultipleItems failed. Falling back to fetching inventory items one by one."); 78
78 items = new InventoryItemBase[itemsRequested.Count]; 79 if (items == null)
79 i = 0;
80 InventoryItemBase item = new InventoryItemBase();
81 item.Owner = m_agentID;
82 foreach (UUID id in itemIDs)
83 { 80 {
84 item.ID = id; 81 // OMG!!! One by one!!! This is fallback code, in case the backend isn't updated
85 items[i++] = m_inventoryService.GetItem(item); 82 m_log.WarnFormat("[FETCH INVENTORY HANDLER]: GetMultipleItems failed. Falling back to fetching inventory items one by one.");
83 items = new InventoryItemBase[itemsRequested.Count];
84 foreach (UUID id in itemIDs)
85 items[i++] = m_inventoryService.GetItem(m_agentID, id);
86 } 86 }
87 } 87 }
88 else
89 {
90 items = new InventoryItemBase[itemsRequested.Count];
91 foreach (UUID id in itemIDs)
92 items[i++] = m_inventoryService.GetItem(UUID.Zero, id);
93 }
88 94
89 foreach (InventoryItemBase item in items) 95 foreach (InventoryItemBase item in items)
90 { 96 {
@@ -93,7 +99,6 @@ namespace OpenSim.Capabilities.Handlers
93 // We don't know the agent that this request belongs to so we'll use the agent id of the item 99 // We don't know the agent that this request belongs to so we'll use the agent id of the item
94 // which will be the same for all items. 100 // which will be the same for all items.
95 llsdReply.agent_id = item.Owner; 101 llsdReply.agent_id = item.Owner;
96
97 llsdReply.items.Array.Add(ConvertInventoryItem(item)); 102 llsdReply.items.Array.Add(ConvertInventoryItem(item));
98 } 103 }
99 } 104 }
@@ -114,7 +119,7 @@ namespace OpenSim.Capabilities.Handlers
114 llsdItem.asset_id = invItem.AssetID; 119 llsdItem.asset_id = invItem.AssetID;
115 llsdItem.created_at = invItem.CreationDate; 120 llsdItem.created_at = invItem.CreationDate;
116 llsdItem.desc = invItem.Description; 121 llsdItem.desc = invItem.Description;
117 llsdItem.flags = (int)invItem.Flags; 122 llsdItem.flags = ((int)invItem.Flags) & 0xff;
118 llsdItem.item_id = invItem.ID; 123 llsdItem.item_id = invItem.ID;
119 llsdItem.name = invItem.Name; 124 llsdItem.name = invItem.Name;
120 llsdItem.parent_id = invItem.Folder; 125 llsdItem.parent_id = invItem.Folder;
@@ -138,4 +143,4 @@ namespace OpenSim.Capabilities.Handlers
138 return llsdItem; 143 return llsdItem;
139 } 144 }
140 } 145 }
141} \ No newline at end of file 146}
diff --git a/OpenSim/Capabilities/Handlers/FetchInventory/FetchInventory2ServerConnector.cs b/OpenSim/Capabilities/Handlers/FetchInventory/FetchInventory2ServerConnector.cs
new file mode 100644
index 0000000..618f075
--- /dev/null
+++ b/OpenSim/Capabilities/Handlers/FetchInventory/FetchInventory2ServerConnector.cs
@@ -0,0 +1,71 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using Nini.Config;
30using OpenSim.Server.Base;
31using OpenSim.Services.Interfaces;
32using OpenSim.Framework.Servers.HttpServer;
33using OpenSim.Server.Handlers.Base;
34using OpenMetaverse;
35
36namespace OpenSim.Capabilities.Handlers
37{
38 public class FetchInventory2ServerConnector : ServiceConnector
39 {
40 private IInventoryService m_InventoryService;
41 private string m_ConfigName = "CapsService";
42
43 public FetchInventory2ServerConnector(IConfigSource config, IHttpServer server, string configName)
44 : base(config, server, configName)
45 {
46 if (configName != String.Empty)
47 m_ConfigName = configName;
48
49 IConfig serverConfig = config.Configs[m_ConfigName];
50 if (serverConfig == null)
51 throw new Exception(String.Format("No section '{0}' in config file", m_ConfigName));
52
53 string invService = serverConfig.GetString("InventoryService", String.Empty);
54
55 if (invService == String.Empty)
56 throw new Exception("No InventoryService in config file");
57
58 Object[] args = new Object[] { config };
59 m_InventoryService = ServerUtils.LoadPlugin<IInventoryService>(invService, args);
60
61 if (m_InventoryService == null)
62 throw new Exception(String.Format("Failed to load InventoryService from {0}; config is {1}", invService, m_ConfigName));
63
64 FetchInventory2Handler fiHandler = new FetchInventory2Handler(m_InventoryService, UUID.Zero);
65 IRequestHandler reqHandler
66 = new RestStreamHandler(
67 "POST", "/CAPS/FetchInventory/", fiHandler.FetchInventoryRequest, "FetchInventory", null);
68 server.AddStreamHandler(reqHandler);
69 }
70 }
71}
diff --git a/OpenSim/Capabilities/Handlers/FetchInventory/Tests/FetchInventory2HandlerTests.cs b/OpenSim/Capabilities/Handlers/FetchInventory/Tests/FetchInventory2HandlerTests.cs
index 8af3c64..94c2c89 100644
--- a/OpenSim/Capabilities/Handlers/FetchInventory/Tests/FetchInventory2HandlerTests.cs
+++ b/OpenSim/Capabilities/Handlers/FetchInventory/Tests/FetchInventory2HandlerTests.cs
@@ -120,7 +120,7 @@ namespace OpenSim.Capabilities.Handlers.FetchInventory.Tests
120 string request = "<llsd><map><key>items</key><array><map><key>item_id</key><uuid>"; 120 string request = "<llsd><map><key>items</key><array><map><key>item_id</key><uuid>";
121 request += "10000000-0000-0000-0000-000000000001"; // Notecard 1 121 request += "10000000-0000-0000-0000-000000000001"; // Notecard 1
122 request += "</uuid></map></array></map></llsd>"; 122 request += "</uuid></map></array></map></llsd>";
123 123
124 string llsdresponse = handler.FetchInventoryRequest(request, "/FETCH", string.Empty, req, resp); 124 string llsdresponse = handler.FetchInventoryRequest(request, "/FETCH", string.Empty, req, resp);
125 125
126 Assert.That(llsdresponse != null, Is.True, "Incorrect null response"); 126 Assert.That(llsdresponse != null, Is.True, "Incorrect null response");
diff --git a/OpenSim/Capabilities/Handlers/FetchInventory/Tests/FetchInventoryDescendents2HandlerTests.cs b/OpenSim/Capabilities/Handlers/FetchInventory/Tests/FetchInventoryDescendents2HandlerTests.cs
index 2d5531a..4143aa3 100644
--- a/OpenSim/Capabilities/Handlers/FetchInventory/Tests/FetchInventoryDescendents2HandlerTests.cs
+++ b/OpenSim/Capabilities/Handlers/FetchInventory/Tests/FetchInventoryDescendents2HandlerTests.cs
@@ -140,7 +140,7 @@ namespace OpenSim.Capabilities.Handlers.FetchInventory.Tests
140 string request = "<llsd><map><key>folders</key><array><map><key>fetch_folders</key><integer>1</integer><key>fetch_items</key><boolean>1</boolean><key>folder_id</key><uuid>"; 140 string request = "<llsd><map><key>folders</key><array><map><key>fetch_folders</key><integer>1</integer><key>fetch_items</key><boolean>1</boolean><key>folder_id</key><uuid>";
141 request += m_rootFolderID; 141 request += m_rootFolderID;
142 request += "</uuid><key>owner_id</key><uuid>00000000-0000-0000-0000-000000000000</uuid><key>sort_order</key><integer>1</integer></map></array></map></llsd>"; 142 request += "</uuid><key>owner_id</key><uuid>00000000-0000-0000-0000-000000000000</uuid><key>sort_order</key><integer>1</integer></map></array></map></llsd>";
143 143
144 string llsdresponse = handler.FetchInventoryDescendentsRequest(request, "/FETCH", string.Empty, req, resp); 144 string llsdresponse = handler.FetchInventoryDescendentsRequest(request, "/FETCH", string.Empty, req, resp);
145 145
146 Assert.That(llsdresponse != null, Is.True, "Incorrect null response"); 146 Assert.That(llsdresponse != null, Is.True, "Incorrect null response");
@@ -203,7 +203,7 @@ namespace OpenSim.Capabilities.Handlers.FetchInventory.Tests
203 203
204 // Make sure that the note card link is included 204 // Make sure that the note card link is included
205 Assert.That(llsdresponse.Contains("Link to notecard"), Is.True, "Link to notecard is missing"); 205 Assert.That(llsdresponse.Contains("Link to notecard"), Is.True, "Link to notecard is missing");
206 206
207 //Make sure the notecard item itself is included 207 //Make sure the notecard item itself is included
208 Assert.That(llsdresponse.Contains("Test Notecard 2"), Is.True, "Notecard 2 item (the source) is missing"); 208 Assert.That(llsdresponse.Contains("Test Notecard 2"), Is.True, "Notecard 2 item (the source) is missing");
209 209
@@ -215,10 +215,11 @@ namespace OpenSim.Capabilities.Handlers.FetchInventory.Tests
215 // Make sure the folder link is included 215 // Make sure the folder link is included
216 Assert.That(llsdresponse.Contains("Link to Objects folder"), Is.True, "Link to Objects folder is missing"); 216 Assert.That(llsdresponse.Contains("Link to Objects folder"), Is.True, "Link to Objects folder is missing");
217 217
218/* contents of link folder are not supposed to be listed
218 // Make sure the objects inside the Objects folder are included 219 // Make sure the objects inside the Objects folder are included
219 // Note: I'm not entirely sure this is needed, but that's what I found in the implementation 220 // Note: I'm not entirely sure this is needed, but that's what I found in the implementation
220 Assert.That(llsdresponse.Contains("Some Object"), Is.True, "Some Object item (contents of the source) is missing"); 221 Assert.That(llsdresponse.Contains("Some Object"), Is.True, "Some Object item (contents of the source) is missing");
221 222*/
222 // Make sure that the source item is before the link item 223 // Make sure that the source item is before the link item
223 pos1 = llsdresponse.IndexOf("Some Object"); 224 pos1 = llsdresponse.IndexOf("Some Object");
224 pos2 = llsdresponse.IndexOf("Link to Objects folder"); 225 pos2 = llsdresponse.IndexOf("Link to Objects folder");
diff --git a/OpenSim/Capabilities/Handlers/GetDisplayNames/GetDisplayNamesHandler.cs b/OpenSim/Capabilities/Handlers/GetDisplayNames/GetDisplayNamesHandler.cs
index 589602d..41cfdb6 100644
--- a/OpenSim/Capabilities/Handlers/GetDisplayNames/GetDisplayNamesHandler.cs
+++ b/OpenSim/Capabilities/Handlers/GetDisplayNames/GetDisplayNamesHandler.cs
@@ -29,8 +29,6 @@ using System;
29using System.Collections; 29using System.Collections;
30using System.Collections.Generic; 30using System.Collections.Generic;
31using System.Collections.Specialized; 31using System.Collections.Specialized;
32using System.Drawing;
33using System.Drawing.Imaging;
34using System.Reflection; 32using System.Reflection;
35using System.IO; 33using System.IO;
36using System.Web; 34using System.Web;
@@ -38,12 +36,7 @@ using log4net;
38using Nini.Config; 36using Nini.Config;
39using OpenMetaverse; 37using OpenMetaverse;
40using OpenMetaverse.StructuredData; 38using OpenMetaverse.StructuredData;
41using OpenMetaverse.Imaging;
42using OpenSim.Framework;
43using OpenSim.Framework.Capabilities;
44using OpenSim.Framework.Servers;
45using OpenSim.Framework.Servers.HttpServer; 39using OpenSim.Framework.Servers.HttpServer;
46using OpenSim.Region.Framework.Interfaces;
47using OpenSim.Services.Interfaces; 40using OpenSim.Services.Interfaces;
48using Caps = OpenSim.Framework.Capabilities.Caps; 41using Caps = OpenSim.Framework.Capabilities.Caps;
49using OSDMap = OpenMetaverse.StructuredData.OSDMap; 42using OSDMap = OpenMetaverse.StructuredData.OSDMap;
@@ -55,7 +48,7 @@ namespace OpenSim.Capabilities.Handlers
55 { 48 {
56 private static readonly ILog m_log = 49 private static readonly ILog m_log =
57 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 50 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
58 private IUserManagement m_UserManagement; 51 protected IUserManagement m_UserManagement;
59 52
60 public GetDisplayNamesHandler(string path, IUserManagement umService, string name, string description) 53 public GetDisplayNamesHandler(string path, IUserManagement umService, string name, string description)
61 : base("GET", path, name, description) 54 : base("GET", path, name, description)
@@ -65,12 +58,11 @@ namespace OpenSim.Capabilities.Handlers
65 58
66 protected override byte[] ProcessRequest(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) 59 protected override byte[] ProcessRequest(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
67 { 60 {
68 m_log.DebugFormat("[GET_DISPLAY_NAMES]: called {0}", httpRequest.Url.Query); 61// m_log.DebugFormat("[GET_DISPLAY_NAMES]: called {0}", httpRequest.Url.Query);
69 62
70 NameValueCollection query = HttpUtility.ParseQueryString(httpRequest.Url.Query); 63 NameValueCollection query = HttpUtility.ParseQueryString(httpRequest.Url.Query);
71 string[] ids = query.GetValues("ids"); 64 string[] ids = query.GetValues("ids");
72 65
73
74 if (m_UserManagement == null) 66 if (m_UserManagement == null)
75 { 67 {
76 m_log.Error("[GET_DISPLAY_NAMES]: Cannot fetch display names without a user management component"); 68 m_log.Error("[GET_DISPLAY_NAMES]: Cannot fetch display names without a user management component");
@@ -78,32 +70,39 @@ namespace OpenSim.Capabilities.Handlers
78 return new byte[0]; 70 return new byte[0];
79 } 71 }
80 72
73 Dictionary<UUID,string> names = m_UserManagement.GetUsersNames(ids);
74
81 OSDMap osdReply = new OSDMap(); 75 OSDMap osdReply = new OSDMap();
82 OSDArray agents = new OSDArray(); 76 OSDArray agents = new OSDArray();
83 77
84 osdReply["agents"] = agents; 78 osdReply["agents"] = agents;
85 foreach (string id in ids) 79 foreach (KeyValuePair<UUID,string> kvp in names)
86 { 80 {
87 UUID uuid = UUID.Zero; 81 if (string.IsNullOrEmpty(kvp.Value))
88 if (UUID.TryParse(id, out uuid)) 82 continue;
89 { 83 if(kvp.Key == UUID.Zero)
90 string name = m_UserManagement.GetUserName(uuid); 84 continue;
91 if (!string.IsNullOrEmpty(name))
92 {
93 string[] parts = name.Split(new char[] {' '});
94 OSDMap osdname = new OSDMap();
95 osdname["display_name_next_update"] = OSD.FromDate(DateTime.MinValue);
96 osdname["display_name_expires"] = OSD.FromDate(DateTime.Now.AddMonths(1));
97 osdname["display_name"] = OSD.FromString(name);
98 osdname["legacy_first_name"] = parts[0];
99 osdname["legacy_last_name"] = parts[1];
100 osdname["username"] = OSD.FromString(name);
101 osdname["id"] = OSD.FromUUID(uuid);
102 osdname["is_display_name_default"] = OSD.FromBoolean(true);
103 85
104 agents.Add(osdname); 86 string[] parts = kvp.Value.Split(new char[] {' '});
105 } 87 OSDMap osdname = new OSDMap();
88 if(parts[0] == "Unknown")
89 {
90 osdname["display_name_next_update"] = OSD.FromDate(DateTime.UtcNow.AddHours(1));
91 osdname["display_name_expires"] = OSD.FromDate(DateTime.UtcNow.AddHours(2));
106 } 92 }
93 else
94 {
95 osdname["display_name_next_update"] = OSD.FromDate(DateTime.UtcNow.AddDays(8));
96 osdname["display_name_expires"] = OSD.FromDate(DateTime.UtcNow.AddMonths(1));
97 }
98 osdname["display_name"] = OSD.FromString(kvp.Value);
99 osdname["legacy_first_name"] = parts[0];
100 osdname["legacy_last_name"] = parts[1];
101 osdname["username"] = OSD.FromString(kvp.Value);
102 osdname["id"] = OSD.FromUUID(kvp.Key);
103 osdname["is_display_name_default"] = OSD.FromBoolean(true);
104
105 agents.Add(osdname);
107 } 106 }
108 107
109 // Full content request 108 // Full content request
@@ -113,8 +112,6 @@ namespace OpenSim.Capabilities.Handlers
113 112
114 string reply = OSDParser.SerializeLLSDXmlString(osdReply); 113 string reply = OSDParser.SerializeLLSDXmlString(osdReply);
115 return System.Text.Encoding.UTF8.GetBytes(reply); 114 return System.Text.Encoding.UTF8.GetBytes(reply);
116
117 } 115 }
118
119 } 116 }
120} \ No newline at end of file 117}
diff --git a/OpenSim/Capabilities/Handlers/GetDisplayNames/GetDisplayNamesServerConnector.cs b/OpenSim/Capabilities/Handlers/GetDisplayNames/GetDisplayNamesServerConnector.cs
index d42de56..32da1c2 100644
--- a/OpenSim/Capabilities/Handlers/GetDisplayNames/GetDisplayNamesServerConnector.cs
+++ b/OpenSim/Capabilities/Handlers/GetDisplayNames/GetDisplayNamesServerConnector.cs
@@ -62,8 +62,6 @@ namespace OpenSim.Capabilities.Handlers
62 if (m_UserManagement == null) 62 if (m_UserManagement == null)
63 throw new Exception(String.Format("Failed to load UserManagement from {0}; config is {1}", umService, m_ConfigName)); 63 throw new Exception(String.Format("Failed to load UserManagement from {0}; config is {1}", umService, m_ConfigName));
64 64
65 string rurl = serverConfig.GetString("GetTextureRedirectURL");
66
67 server.AddStreamHandler( 65 server.AddStreamHandler(
68 new GetDisplayNamesHandler("/CAPS/agents/", m_UserManagement, "GetDisplayNames", null)); 66 new GetDisplayNamesHandler("/CAPS/agents/", m_UserManagement, "GetDisplayNames", null));
69 } 67 }
diff --git a/OpenSim/Capabilities/Handlers/GetMesh/GetMeshHandler.cs b/OpenSim/Capabilities/Handlers/GetMesh/GetMeshHandler.cs
index 6b67da1..a9b81f3 100644
--- a/OpenSim/Capabilities/Handlers/GetMesh/GetMeshHandler.cs
+++ b/OpenSim/Capabilities/Handlers/GetMesh/GetMeshHandler.cs
@@ -25,224 +25,242 @@
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */ 26 */
27 27
28using System;
29using System.Collections;
30using System.Collections.Specialized;
31using System.Reflection;
32using System.IO;
33using System.Web;
28using log4net; 34using log4net;
35using Nini.Config;
29using OpenMetaverse; 36using OpenMetaverse;
30using OpenMetaverse.Imaging; 37using OpenMetaverse.StructuredData;
31using OpenSim.Framework; 38using OpenSim.Framework;
39using OpenSim.Framework.Servers;
32using OpenSim.Framework.Servers.HttpServer; 40using OpenSim.Framework.Servers.HttpServer;
33using OpenSim.Services.Interfaces; 41using OpenSim.Services.Interfaces;
34using System; 42using Caps = OpenSim.Framework.Capabilities.Caps;
35using System.Collections.Specialized; 43
36using System.Drawing; 44
37using System.Drawing.Imaging; 45
38using System.IO;
39using System.Reflection;
40using System.Web;
41 46
42namespace OpenSim.Capabilities.Handlers 47namespace OpenSim.Capabilities.Handlers
43{ 48{
44 public class GetMeshHandler : BaseStreamHandler 49 public class GetMeshHandler
45 { 50 {
46 private static readonly ILog m_log = 51 private static readonly ILog m_log =
47 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 52 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
53
48 private IAssetService m_assetService; 54 private IAssetService m_assetService;
49 55
50 // TODO: Change this to a config option 56 public const string DefaultFormat = "vnd.ll.mesh";
51 private string m_RedirectURL = null;
52 57
53 public GetMeshHandler(string path, IAssetService assService, string name, string description, string redirectURL) 58 public GetMeshHandler(IAssetService assService)
54 : base("GET", path, name, description)
55 { 59 {
56 m_assetService = assService; 60 m_assetService = assService;
57 m_RedirectURL = redirectURL;
58 if (m_RedirectURL != null && !m_RedirectURL.EndsWith("/"))
59 m_RedirectURL += "/";
60 } 61 }
61 62 public Hashtable Handle(Hashtable request)
62 protected override byte[] ProcessRequest(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
63 { 63 {
64 // Try to parse the texture ID from the request URL 64 Hashtable ret = new Hashtable();
65 NameValueCollection query = HttpUtility.ParseQueryString(httpRequest.Url.Query); 65 ret["int_response_code"] = (int)System.Net.HttpStatusCode.NotFound;
66 string textureStr = query.GetOne("mesh_id"); 66 ret["content_type"] = "text/plain";
67 ret["keepalive"] = false;
68 ret["reusecontext"] = false;
69 ret["int_bytes"] = 0;
70 ret["int_lod"] = 0;
71 string MeshStr = (string)request["mesh_id"];
72
73
74 //m_log.DebugFormat("[GETMESH]: called {0}", MeshStr);
67 75
68 if (m_assetService == null) 76 if (m_assetService == null)
69 { 77 {
70 m_log.Error("[GETMESH]: Cannot fetch mesh " + textureStr + " without an asset service"); 78 m_log.Error("[GETMESH]: Cannot fetch mesh " + MeshStr + " without an asset service");
71 httpResponse.StatusCode = (int)System.Net.HttpStatusCode.NotFound;
72 } 79 }
73 80
74 UUID meshID; 81 UUID meshID;
75 if (!String.IsNullOrEmpty(textureStr) && UUID.TryParse(textureStr, out meshID)) 82 if (!String.IsNullOrEmpty(MeshStr) && UUID.TryParse(MeshStr, out meshID))
76 { 83 {
77 // OK, we have an array with preferred formats, possibly with only one entry 84 // m_log.DebugFormat("[GETMESH]: Received request for mesh id {0}", meshID);
78
79 httpResponse.StatusCode = (int)System.Net.HttpStatusCode.NotFound;
80 AssetBase mesh;
81
82 if (!String.IsNullOrEmpty(m_RedirectURL))
83 {
84 // Only try to fetch locally cached meshes. Misses are redirected
85 mesh = m_assetService.GetCached(meshID.ToString());
86 85
87 if (mesh != null)
88 {
89 if (mesh.Type != (sbyte)AssetType.Mesh)
90 {
91 httpResponse.StatusCode = (int)System.Net.HttpStatusCode.NotFound;
92 }
93 WriteMeshData(httpRequest, httpResponse, mesh);
94 }
95 else
96 {
97 string textureUrl = m_RedirectURL + "?mesh_id="+ meshID.ToString();
98 m_log.Debug("[GETMESH]: Redirecting mesh request to " + textureUrl);
99 httpResponse.StatusCode = (int)OSHttpStatusCode.RedirectMovedPermanently;
100 httpResponse.RedirectLocation = textureUrl;
101 return null;
102 }
103 }
104 else // no redirect
105 {
106 // try the cache
107 mesh = m_assetService.GetCached(meshID.ToString());
108 86
109 if (mesh == null) 87 ret = ProcessGetMesh(request, UUID.Zero, null);
110 {
111 // Fetch locally or remotely. Misses return a 404
112 mesh = m_assetService.Get(meshID.ToString());
113 88
114 if (mesh != null)
115 {
116 if (mesh.Type != (sbyte)AssetType.Mesh)
117 {
118 httpResponse.StatusCode = (int)System.Net.HttpStatusCode.NotFound;
119 return null;
120 }
121 WriteMeshData(httpRequest, httpResponse, mesh);
122 return null;
123 }
124 }
125 else // it was on the cache
126 {
127 if (mesh.Type != (sbyte)AssetType.Mesh)
128 {
129 httpResponse.StatusCode = (int)System.Net.HttpStatusCode.NotFound;
130 return null;
131 }
132 WriteMeshData(httpRequest, httpResponse, mesh);
133 return null;
134 }
135 }
136 89
137 // not found
138 httpResponse.StatusCode = (int)System.Net.HttpStatusCode.NotFound;
139 return null;
140 } 90 }
141 else 91 else
142 { 92 {
143 m_log.Warn("[GETTEXTURE]: Failed to parse a mesh_id from GetMesh request: " + httpRequest.Url); 93 m_log.Warn("[GETMESH]: Failed to parse a mesh_id from GetMesh request: " + (string)request["uri"]);
144 } 94 }
145 95
146 return null;
147 }
148 96
149 private void WriteMeshData(IOSHttpRequest request, IOSHttpResponse response, AssetBase texture) 97 return ret;
98 }
99 public Hashtable ProcessGetMesh(Hashtable request, UUID AgentId, Caps cap)
150 { 100 {
151 string range = request.Headers.GetOne("Range"); 101 Hashtable responsedata = new Hashtable();
102 responsedata["int_response_code"] = 400; //501; //410; //404;
103 responsedata["content_type"] = "text/plain";
104 responsedata["keepalive"] = false;
105 responsedata["str_response_string"] = "Request wasn't what was expected";
106 responsedata["reusecontext"] = false;
107 responsedata["int_lod"] = 0;
108 responsedata["int_bytes"] = 0;
109
110 string meshStr = string.Empty;
152 111
153 if (!String.IsNullOrEmpty(range)) 112 if (request.ContainsKey("mesh_id"))
113 meshStr = request["mesh_id"].ToString();
114
115 UUID meshID = UUID.Zero;
116 if (!String.IsNullOrEmpty(meshStr) && UUID.TryParse(meshStr, out meshID))
154 { 117 {
155 // Range request 118 if (m_assetService == null)
156 int start, end;
157 if (TryParseRange(range, out start, out end))
158 { 119 {
159 // Before clamping start make sure we can satisfy it in order to avoid 120 responsedata["int_response_code"] = 404; //501; //410; //404;
160 // sending back the last byte instead of an error status 121 responsedata["content_type"] = "text/plain";
161 if (start >= texture.Data.Length) 122 responsedata["keepalive"] = false;
162 { 123 responsedata["str_response_string"] = "The asset service is unavailable. So is your mesh.";
163 response.StatusCode = (int)System.Net.HttpStatusCode.PartialContent; 124 responsedata["reusecontext"] = false;
164 response.ContentType = texture.Metadata.ContentType; 125 return responsedata;
165 } 126 }
166 else 127
128 AssetBase mesh = m_assetService.Get(meshID.ToString());
129
130 if (mesh != null)
131 {
132 if (mesh.Type == (SByte)AssetType.Mesh)
167 { 133 {
168 // Handle the case where no second range value was given. This is equivalent to requesting
169 // the rest of the entity.
170 if (end == -1)
171 end = int.MaxValue;
172 134
173 end = Utils.Clamp(end, 0, texture.Data.Length - 1); 135 Hashtable headers = new Hashtable();
174 start = Utils.Clamp(start, 0, end); 136 responsedata["headers"] = headers;
175 int len = end - start + 1; 137
138 string range = String.Empty;
139
140 if (((Hashtable)request["headers"])["range"] != null)
141 range = (string)((Hashtable)request["headers"])["range"];
176 142
177 if (0 == start && len == texture.Data.Length) 143 else if (((Hashtable)request["headers"])["Range"] != null)
144 range = (string)((Hashtable)request["headers"])["Range"];
145
146 if (!String.IsNullOrEmpty(range)) // Mesh Asset LOD // Physics
178 { 147 {
179 response.StatusCode = (int)System.Net.HttpStatusCode.OK; 148 // Range request
149 int start, end;
150 if (TryParseRange(range, out start, out end))
151 {
152 // Before clamping start make sure we can satisfy it in order to avoid
153 // sending back the last byte instead of an error status
154 if (start >= mesh.Data.Length)
155 {
156 responsedata["int_response_code"] = 404; //501; //410; //404;
157 responsedata["content_type"] = "text/plain";
158 responsedata["keepalive"] = false;
159 responsedata["str_response_string"] = "This range doesnt exist.";
160 responsedata["reusecontext"] = false;
161 responsedata["int_lod"] = 3;
162 return responsedata;
163 }
164 else
165 {
166 end = Utils.Clamp(end, 0, mesh.Data.Length - 1);
167 start = Utils.Clamp(start, 0, end);
168 int len = end - start + 1;
169
170 //m_log.Debug("Serving " + start + " to " + end + " of " + texture.Data.Length + " bytes for texture " + texture.ID);
171
172 if (start > 20000)
173 {
174 responsedata["int_lod"] = 3;
175 }
176 else if (start < 4097)
177 {
178 responsedata["int_lod"] = 1;
179 }
180 else
181 {
182 responsedata["int_lod"] = 2;
183 }
184
185
186 if (start == 0 && len == mesh.Data.Length) // well redudante maybe
187 {
188 responsedata["int_response_code"] = (int)System.Net.HttpStatusCode.OK;
189 responsedata["bin_response_data"] = mesh.Data;
190 responsedata["int_bytes"] = mesh.Data.Length;
191 responsedata["reusecontext"] = false;
192 responsedata["int_lod"] = 3;
193
194 }
195 else
196 {
197 responsedata["int_response_code"] =
198 (int)System.Net.HttpStatusCode.PartialContent;
199 headers["Content-Range"] = String.Format("bytes {0}-{1}/{2}", start, end,
200 mesh.Data.Length);
201
202 byte[] d = new byte[len];
203 Array.Copy(mesh.Data, start, d, 0, len);
204 responsedata["bin_response_data"] = d;
205 responsedata["int_bytes"] = len;
206 responsedata["reusecontext"] = false;
207 }
208 }
209 }
210 else
211 {
212 m_log.Warn("[GETMESH]: Failed to parse a range from GetMesh request, sending full asset: " + (string)request["uri"]);
213 responsedata["str_response_string"] = Convert.ToBase64String(mesh.Data);
214 responsedata["content_type"] = "application/vnd.ll.mesh";
215 responsedata["int_response_code"] = 200;
216 responsedata["reusecontext"] = false;
217 responsedata["int_lod"] = 3;
218 }
180 } 219 }
181 else 220 else
182 { 221 {
183 response.StatusCode = (int)System.Net.HttpStatusCode.PartialContent; 222 responsedata["str_response_string"] = Convert.ToBase64String(mesh.Data);
184 response.AddHeader("Content-Range", String.Format("bytes {0}-{1}/{2}", start, end, texture.Data.Length)); 223 responsedata["content_type"] = "application/vnd.ll.mesh";
224 responsedata["int_response_code"] = 200;
225 responsedata["reusecontext"] = false;
226 responsedata["int_lod"] = 3;
185 } 227 }
186 228 }
187 response.ContentLength = len; 229 // Optionally add additional mesh types here
188 response.ContentType = "application/vnd.ll.mesh"; 230 else
189 231 {
190 response.Body.Write(texture.Data, start, len); 232 responsedata["int_response_code"] = 404; //501; //410; //404;
233 responsedata["content_type"] = "text/plain";
234 responsedata["keepalive"] = false;
235 responsedata["str_response_string"] = "Unfortunately, this asset isn't a mesh.";
236 responsedata["reusecontext"] = false;
237 responsedata["int_lod"] = 1;
238 return responsedata;
191 } 239 }
192 } 240 }
193 else 241 else
194 { 242 {
195 m_log.Warn("[GETMESH]: Malformed Range header: " + range); 243 responsedata["int_response_code"] = 404; //501; //410; //404;
196 response.StatusCode = (int)System.Net.HttpStatusCode.BadRequest; 244 responsedata["content_type"] = "text/plain";
245 responsedata["keepalive"] = false;
246 responsedata["str_response_string"] = "Your Mesh wasn't found. Sorry!";
247 responsedata["reusecontext"] = false;
248 responsedata["int_lod"] = 0;
249 return responsedata;
197 } 250 }
198 } 251 }
199 else
200 {
201 // Full content request
202 response.StatusCode = (int)System.Net.HttpStatusCode.OK;
203 response.ContentLength = texture.Data.Length;
204 response.ContentType = "application/vnd.ll.mesh";
205 response.Body.Write(texture.Data, 0, texture.Data.Length);
206 }
207 }
208 252
209 /// <summary> 253 return responsedata;
210 /// Parse a range header. 254 }
211 /// </summary>
212 /// <remarks>
213 /// As per http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html,
214 /// this obeys range headers with two values (e.g. 533-4165) and no second value (e.g. 533-).
215 /// Where there is no value, -1 is returned.
216 /// FIXME: Need to cover the case where only a second value is specified (e.g. -4165), probably by returning -1
217 /// for start.</remarks>
218 /// <returns></returns>
219 /// <param name='header'></param>
220 /// <param name='start'>Start of the range. Undefined if this was not a number.</param>
221 /// <param name='end'>End of the range. Will be -1 if no end specified. Undefined if there was a raw string but this was not a number.</param>
222 private bool TryParseRange(string header, out int start, out int end) 255 private bool TryParseRange(string header, out int start, out int end)
223 { 256 {
224 start = end = 0;
225
226 if (header.StartsWith("bytes=")) 257 if (header.StartsWith("bytes="))
227 { 258 {
228 string[] rangeValues = header.Substring(6).Split('-'); 259 string[] rangeValues = header.Substring(6).Split('-');
229
230 if (rangeValues.Length == 2) 260 if (rangeValues.Length == 2)
231 { 261 {
232 if (!Int32.TryParse(rangeValues[0], out start)) 262 if (Int32.TryParse(rangeValues[0], out start) && Int32.TryParse(rangeValues[1], out end))
233 return false;
234
235 string rawEnd = rangeValues[1];
236
237 if (rawEnd == "")
238 {
239 end = -1;
240 return true; 263 return true;
241 }
242 else if (Int32.TryParse(rawEnd, out end))
243 {
244 return true;
245 }
246 } 264 }
247 } 265 }
248 266
diff --git a/OpenSim/Capabilities/Handlers/GetMesh/GetMeshServerConnector.cs b/OpenSim/Capabilities/Handlers/GetMesh/GetMeshServerConnector.cs
index 19de3cf..b494aa4 100644
--- a/OpenSim/Capabilities/Handlers/GetMesh/GetMeshServerConnector.cs
+++ b/OpenSim/Capabilities/Handlers/GetMesh/GetMeshServerConnector.cs
@@ -64,13 +64,15 @@ namespace OpenSim.Capabilities.Handlers
64 64
65 string rurl = serverConfig.GetString("GetMeshRedirectURL"); 65 string rurl = serverConfig.GetString("GetMeshRedirectURL");
66 66
67 server.AddStreamHandler( 67 GetMeshHandler gmeshHandler = new GetMeshHandler(m_AssetService);
68 new GetTextureHandler("/CAPS/GetMesh/" /*+ UUID.Random() */, m_AssetService, "GetMesh", null, rurl)); 68 IRequestHandler reqHandler
69 69 = new RestHTTPHandler(
70 rurl = serverConfig.GetString("GetMesh2RedirectURL"); 70 "GET",
71 71 "/CAPS/" + UUID.Random(),
72 server.AddStreamHandler( 72 httpMethod => gmeshHandler.ProcessGetMesh(httpMethod, UUID.Zero, null),
73 new GetTextureHandler("/CAPS/GetMesh2/" /*+ UUID.Random() */, m_AssetService, "GetMesh2", null, rurl)); 73 "GetMesh",
74 null);
75 server.AddStreamHandler(reqHandler); ;
74 } 76 }
75 } 77 }
76} \ No newline at end of file 78} \ No newline at end of file
diff --git a/OpenSim/Capabilities/Handlers/GetTexture/GetTextureHandler.cs b/OpenSim/Capabilities/Handlers/GetTexture/GetTextureHandler.cs
index 828e943..e73cf9e 100644
--- a/OpenSim/Capabilities/Handlers/GetTexture/GetTextureHandler.cs
+++ b/OpenSim/Capabilities/Handlers/GetTexture/GetTextureHandler.cs
@@ -47,46 +47,43 @@ using Caps = OpenSim.Framework.Capabilities.Caps;
47 47
48namespace OpenSim.Capabilities.Handlers 48namespace OpenSim.Capabilities.Handlers
49{ 49{
50 public class GetTextureHandler : BaseStreamHandler 50 public class GetTextureHandler
51 { 51 {
52 private static readonly ILog m_log = 52 private static readonly ILog m_log =
53 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 53 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
54
54 private IAssetService m_assetService; 55 private IAssetService m_assetService;
55 56
56 public const string DefaultFormat = "x-j2c"; 57 public const string DefaultFormat = "x-j2c";
57 58
58 // TODO: Change this to a config option 59 public GetTextureHandler(IAssetService assService)
59 private string m_RedirectURL = null;
60
61 public GetTextureHandler(string path, IAssetService assService, string name, string description, string redirectURL)
62 : base("GET", path, name, description)
63 { 60 {
64 m_assetService = assService; 61 m_assetService = assService;
65 m_RedirectURL = redirectURL;
66 if (m_RedirectURL != null && !m_RedirectURL.EndsWith("/"))
67 m_RedirectURL += "/";
68 } 62 }
69 63
70 protected override byte[] ProcessRequest(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) 64 public Hashtable Handle(Hashtable request)
71 { 65 {
72 // Try to parse the texture ID from the request URL 66 Hashtable ret = new Hashtable();
73 NameValueCollection query = HttpUtility.ParseQueryString(httpRequest.Url.Query); 67 ret["int_response_code"] = (int)System.Net.HttpStatusCode.NotFound;
74 string textureStr = query.GetOne("texture_id"); 68 ret["content_type"] = "text/plain";
75 string format = query.GetOne("format"); 69 ret["keepalive"] = false;
70 ret["reusecontext"] = false;
71 ret["int_bytes"] = 0;
72 string textureStr = (string)request["texture_id"];
73 string format = (string)request["format"];
76 74
77 //m_log.DebugFormat("[GETTEXTURE]: called {0}", textureStr); 75 //m_log.DebugFormat("[GETTEXTURE]: called {0}", textureStr);
78 76
79 if (m_assetService == null) 77 if (m_assetService == null)
80 { 78 {
81 m_log.Error("[GETTEXTURE]: Cannot fetch texture " + textureStr + " without an asset service"); 79 m_log.Error("[GETTEXTURE]: Cannot fetch texture " + textureStr + " without an asset service");
82 httpResponse.StatusCode = (int)System.Net.HttpStatusCode.NotFound;
83 } 80 }
84 81
85 UUID textureID; 82 UUID textureID;
86 if (!String.IsNullOrEmpty(textureStr) && UUID.TryParse(textureStr, out textureID)) 83 if (!String.IsNullOrEmpty(textureStr) && UUID.TryParse(textureStr, out textureID))
87 { 84 {
88// m_log.DebugFormat("[GETTEXTURE]: Received request for texture id {0}", textureID); 85// m_log.DebugFormat("[GETTEXTURE]: Received request for texture id {0}", textureID);
89 86
90 string[] formats; 87 string[] formats;
91 if (!string.IsNullOrEmpty(format)) 88 if (!string.IsNullOrEmpty(format))
92 { 89 {
@@ -94,41 +91,52 @@ namespace OpenSim.Capabilities.Handlers
94 } 91 }
95 else 92 else
96 { 93 {
97 formats = WebUtil.GetPreferredImageTypes(httpRequest.Headers.Get("Accept")); 94 formats = new string[1] { DefaultFormat }; // default
95 if (((Hashtable)request["headers"])["Accept"] != null)
96 formats = WebUtil.GetPreferredImageTypes((string)((Hashtable)request["headers"])["Accept"]);
98 if (formats.Length == 0) 97 if (formats.Length == 0)
99 formats = new string[1] { DefaultFormat }; // default 98 formats = new string[1] { DefaultFormat }; // default
100 99
101 } 100 }
102 // OK, we have an array with preferred formats, possibly with only one entry 101 // OK, we have an array with preferred formats, possibly with only one entry
103 102 bool foundtexture = false;
104 httpResponse.StatusCode = (int)System.Net.HttpStatusCode.NotFound;
105 foreach (string f in formats) 103 foreach (string f in formats)
106 { 104 {
107 if (FetchTexture(httpRequest, httpResponse, textureID, f)) 105 foundtexture = FetchTexture(request, ret, textureID, f);
106 if (foundtexture)
108 break; 107 break;
109 } 108 }
109 if (!foundtexture)
110 {
111 ret["int_response_code"] = 404;
112 ret["error_status_text"] = "not found";
113 ret["str_response_string"] = "not found";
114 ret["content_type"] = "text/plain";
115 ret["keepalive"] = false;
116 ret["reusecontext"] = false;
117 ret["int_bytes"] = 0;
118 }
110 } 119 }
111 else 120 else
112 { 121 {
113 m_log.Warn("[GETTEXTURE]: Failed to parse a texture_id from GetTexture request: " + httpRequest.Url); 122 m_log.Warn("[GETTEXTURE]: Failed to parse a texture_id from GetTexture request: " + (string)request["uri"]);
114 } 123 }
115 124
116// m_log.DebugFormat( 125// m_log.DebugFormat(
117// "[GETTEXTURE]: For texture {0} sending back response {1}, data length {2}", 126// "[GETTEXTURE]: For texture {0} sending back response {1}, data length {2}",
118// textureID, httpResponse.StatusCode, httpResponse.ContentLength); 127// textureID, httpResponse.StatusCode, httpResponse.ContentLength);
119 128 return ret;
120 return null;
121 } 129 }
122 130
123 /// <summary> 131 /// <summary>
124 /// 132 ///
125 /// </summary> 133 /// </summary>
126 /// <param name="httpRequest"></param> 134 /// <param name="httpRequest"></param>
127 /// <param name="httpResponse"></param> 135 /// <param name="httpResponse"></param>
128 /// <param name="textureID"></param> 136 /// <param name="textureID"></param>
129 /// <param name="format"></param> 137 /// <param name="format"></param>
130 /// <returns>False for "caller try another codec"; true otherwise</returns> 138 /// <returns>False for "caller try another codec"; true otherwise</returns>
131 private bool FetchTexture(IOSHttpRequest httpRequest, IOSHttpResponse httpResponse, UUID textureID, string format) 139 private bool FetchTexture(Hashtable request, Hashtable response, UUID textureID, string format)
132 { 140 {
133// m_log.DebugFormat("[GETTEXTURE]: {0} with requested format {1}", textureID, format); 141// m_log.DebugFormat("[GETTEXTURE]: {0} with requested format {1}", textureID, format);
134 AssetBase texture; 142 AssetBase texture;
@@ -137,86 +145,70 @@ namespace OpenSim.Capabilities.Handlers
137 if (format != DefaultFormat) 145 if (format != DefaultFormat)
138 fullID = fullID + "-" + format; 146 fullID = fullID + "-" + format;
139 147
140 if (!String.IsNullOrEmpty(m_RedirectURL)) 148 // try the cache
149 texture = m_assetService.GetCached(fullID);
150
151 if (texture == null)
141 { 152 {
142 // Only try to fetch locally cached textures. Misses are redirected 153 //m_log.DebugFormat("[GETTEXTURE]: texture was not in the cache");
143 texture = m_assetService.GetCached(fullID); 154
155 // Fetch locally or remotely. Misses return a 404
156 texture = m_assetService.Get(textureID.ToString());
144 157
145 if (texture != null) 158 if (texture != null)
146 { 159 {
147 if (texture.Type != (sbyte)AssetType.Texture) 160 if (texture.Type != (sbyte)AssetType.Texture)
161 return true;
162
163 if (format == DefaultFormat)
148 { 164 {
149 httpResponse.StatusCode = (int)System.Net.HttpStatusCode.NotFound; 165 WriteTextureData(request, response, texture, format);
166 return true;
167 }
168 else
169 {
170 AssetBase newTexture = new AssetBase(texture.ID + "-" + format, texture.Name, (sbyte)AssetType.Texture, texture.Metadata.CreatorID);
171 newTexture.Data = ConvertTextureData(texture, format);
172 if (newTexture.Data.Length == 0)
173 return false; // !!! Caller try another codec, please!
174
175 newTexture.Flags = AssetFlags.Collectable;
176 newTexture.Temporary = true;
177 newTexture.Local = true;
178 m_assetService.Store(newTexture);
179 WriteTextureData(request, response, newTexture, format);
150 return true; 180 return true;
151 } 181 }
152 WriteTextureData(httpRequest, httpResponse, texture, format);
153 }
154 else
155 {
156 string textureUrl = m_RedirectURL + "?texture_id="+ textureID.ToString();
157 m_log.Debug("[GETTEXTURE]: Redirecting texture request to " + textureUrl);
158 httpResponse.StatusCode = (int)OSHttpStatusCode.RedirectMovedPermanently;
159 httpResponse.RedirectLocation = textureUrl;
160 return true;
161 } 182 }
162 } 183 }
163 else // no redirect 184 else // it was on the cache
164 { 185 {
165 // try the cache 186 //m_log.DebugFormat("[GETTEXTURE]: texture was in the cache");
166 texture = m_assetService.GetCached(fullID); 187 WriteTextureData(request, response, texture, format);
188 return true;
189 }
167 190
168 if (texture == null) 191 //response = new Hashtable();
169 {
170// m_log.DebugFormat("[GETTEXTURE]: texture was not in the cache");
171
172 // Fetch locally or remotely. Misses return a 404
173 texture = m_assetService.Get(textureID.ToString());
174 192
175 if (texture != null)
176 {
177 if (texture.Type != (sbyte)AssetType.Texture)
178 {
179 httpResponse.StatusCode = (int)System.Net.HttpStatusCode.NotFound;
180 return true;
181 }
182 if (format == DefaultFormat)
183 {
184 WriteTextureData(httpRequest, httpResponse, texture, format);
185 return true;
186 }
187 else
188 {
189 AssetBase newTexture = new AssetBase(texture.ID + "-" + format, texture.Name, (sbyte)AssetType.Texture, texture.Metadata.CreatorID);
190 newTexture.Data = ConvertTextureData(texture, format);
191 if (newTexture.Data.Length == 0)
192 return false; // !!! Caller try another codec, please!
193
194 newTexture.Flags = AssetFlags.Collectable;
195 newTexture.Temporary = true;
196 newTexture.Local = true;
197 m_assetService.Store(newTexture);
198 WriteTextureData(httpRequest, httpResponse, newTexture, format);
199 return true;
200 }
201 }
202 }
203 else // it was on the cache
204 {
205// m_log.DebugFormat("[GETTEXTURE]: texture was in the cache");
206 WriteTextureData(httpRequest, httpResponse, texture, format);
207 return true;
208 }
209 }
210 193
194 //WriteTextureData(request,response,null,format);
211 // not found 195 // not found
212// m_log.Warn("[GETTEXTURE]: Texture " + textureID + " not found"); 196 //m_log.Warn("[GETTEXTURE]: Texture " + textureID + " not found");
213 httpResponse.StatusCode = (int)System.Net.HttpStatusCode.NotFound; 197 return false;
214 return true;
215 } 198 }
216 199
217 private void WriteTextureData(IOSHttpRequest request, IOSHttpResponse response, AssetBase texture, string format) 200 private void WriteTextureData(Hashtable request, Hashtable response, AssetBase texture, string format)
218 { 201 {
219 string range = request.Headers.GetOne("Range"); 202 Hashtable headers = new Hashtable();
203 response["headers"] = headers;
204
205 string range = String.Empty;
206
207 if (((Hashtable)request["headers"])["range"] != null)
208 range = (string)((Hashtable)request["headers"])["range"];
209
210 else if (((Hashtable)request["headers"])["Range"] != null)
211 range = (string)((Hashtable)request["headers"])["Range"];
220 212
221 if (!String.IsNullOrEmpty(range)) // JP2's only 213 if (!String.IsNullOrEmpty(range)) // JP2's only
222 { 214 {
@@ -244,10 +236,8 @@ namespace OpenSim.Capabilities.Handlers
244 // However, if we return PartialContent (or OK) instead, the viewer will display that resolution. 236 // However, if we return PartialContent (or OK) instead, the viewer will display that resolution.
245 237
246// response.StatusCode = (int)System.Net.HttpStatusCode.RequestedRangeNotSatisfiable; 238// response.StatusCode = (int)System.Net.HttpStatusCode.RequestedRangeNotSatisfiable;
247// response.AddHeader("Content-Range", String.Format("bytes */{0}", texture.Data.Length)); 239 // viewers don't seem to handle RequestedRangeNotSatisfiable and keep retrying with same parameters
248// response.StatusCode = (int)System.Net.HttpStatusCode.OK; 240 response["int_response_code"] = (int)System.Net.HttpStatusCode.NotFound;
249 response.StatusCode = (int)System.Net.HttpStatusCode.PartialContent;
250 response.ContentType = texture.Metadata.ContentType;
251 } 241 }
252 else 242 else
253 { 243 {
@@ -262,41 +252,46 @@ namespace OpenSim.Capabilities.Handlers
262 252
263// m_log.Debug("Serving " + start + " to " + end + " of " + texture.Data.Length + " bytes for texture " + texture.ID); 253// m_log.Debug("Serving " + start + " to " + end + " of " + texture.Data.Length + " bytes for texture " + texture.ID);
264 254
265 // Always return PartialContent, even if the range covered the entire data length 255 response["content-type"] = texture.Metadata.ContentType;
266 // We were accidentally sending back 404 before in this situation 256
267 // https://issues.apache.org/bugzilla/show_bug.cgi?id=51878 supports sending 206 even if the 257 if (start == 0 && len == texture.Data.Length) // well redudante maybe
268 // entire range is requested, and viewer 3.2.2 (and very probably earlier) seems fine with this. 258 {
269 // 259 response["int_response_code"] = (int)System.Net.HttpStatusCode.OK;
270 // We also do not want to send back OK even if the whole range was satisfiable since this causes 260 response["bin_response_data"] = texture.Data;
271 // HTTP textures on at least Imprudence 1.4.0-beta2 to never display the final texture quality. 261 response["int_bytes"] = texture.Data.Length;
272// if (end > maxEnd) 262 }
273// response.StatusCode = (int)System.Net.HttpStatusCode.OK; 263 else
274// else 264 {
275 response.StatusCode = (int)System.Net.HttpStatusCode.PartialContent; 265 response["int_response_code"] = (int)System.Net.HttpStatusCode.PartialContent;
276 266 headers["Content-Range"] = String.Format("bytes {0}-{1}/{2}", start, end, texture.Data.Length);
277 response.ContentLength = len; 267
278 response.ContentType = texture.Metadata.ContentType; 268 byte[] d = new byte[len];
279 response.AddHeader("Content-Range", String.Format("bytes {0}-{1}/{2}", start, end, texture.Data.Length)); 269 Array.Copy(texture.Data, start, d, 0, len);
280 270 response["bin_response_data"] = d;
281 response.Body.Write(texture.Data, start, len); 271 response["int_bytes"] = len;
272 }
273// response.Body.Write(texture.Data, start, len);
282 } 274 }
283 } 275 }
284 else 276 else
285 { 277 {
286 m_log.Warn("[GETTEXTURE]: Malformed Range header: " + range); 278 m_log.Warn("[GETTEXTURE]: Malformed Range header: " + range);
287 response.StatusCode = (int)System.Net.HttpStatusCode.BadRequest; 279 response["int_response_code"] = (int)System.Net.HttpStatusCode.BadRequest;
288 } 280 }
289 } 281 }
290 else // JP2's or other formats 282 else // JP2's or other formats
291 { 283 {
292 // Full content request 284 // Full content request
293 response.StatusCode = (int)System.Net.HttpStatusCode.OK; 285 response["int_response_code"] = (int)System.Net.HttpStatusCode.OK;
294 response.ContentLength = texture.Data.Length;
295 if (format == DefaultFormat) 286 if (format == DefaultFormat)
296 response.ContentType = texture.Metadata.ContentType; 287 response["content_type"] = texture.Metadata.ContentType;
297 else 288 else
298 response.ContentType = "image/" + format; 289 response["content_type"] = "image/" + format;
299 response.Body.Write(texture.Data, 0, texture.Data.Length); 290
291 response["bin_response_data"] = texture.Data;
292 response["int_bytes"] = texture.Data.Length;
293
294// response.Body.Write(texture.Data, 0, texture.Data.Length);
300 } 295 }
301 296
302// if (response.StatusCode < 200 || response.StatusCode > 299) 297// if (response.StatusCode < 200 || response.StatusCode > 299)
@@ -359,36 +354,35 @@ namespace OpenSim.Capabilities.Handlers
359 byte[] data = new byte[0]; 354 byte[] data = new byte[0];
360 355
361 MemoryStream imgstream = new MemoryStream(); 356 MemoryStream imgstream = new MemoryStream();
362 Bitmap mTexture = new Bitmap(1, 1); 357 Bitmap mTexture = null;
363 ManagedImage managedImage; 358 ManagedImage managedImage = null;
364 Image image = (Image)mTexture; 359 Image image = null;
365 360
366 try 361 try
367 { 362 {
368 // Taking our jpeg2000 data, decoding it, then saving it to a byte array with regular data 363 // Taking our jpeg2000 data, decoding it, then saving it to a byte array with regular data
369 364
370 imgstream = new MemoryStream();
371
372 // Decode image to System.Drawing.Image 365 // Decode image to System.Drawing.Image
373 if (OpenJPEG.DecodeToImage(texture.Data, out managedImage, out image)) 366 if (OpenJPEG.DecodeToImage(texture.Data, out managedImage, out image) && image != null)
374 { 367 {
375 // Save to bitmap 368 // Save to bitmap
376 mTexture = new Bitmap(image); 369 mTexture = new Bitmap(image);
377 370
378 EncoderParameters myEncoderParameters = new EncoderParameters(); 371 using(EncoderParameters myEncoderParameters = new EncoderParameters())
379 myEncoderParameters.Param[0] = new EncoderParameter(Encoder.Quality, 95L);
380
381 // Save bitmap to stream
382 ImageCodecInfo codec = GetEncoderInfo("image/" + format);
383 if (codec != null)
384 { 372 {
385 mTexture.Save(imgstream, codec, myEncoderParameters); 373 myEncoderParameters.Param[0] = new EncoderParameter(Encoder.Quality,95L);
374
375 // Save bitmap to stream
376 ImageCodecInfo codec = GetEncoderInfo("image/" + format);
377 if (codec != null)
378 {
379 mTexture.Save(imgstream, codec, myEncoderParameters);
386 // Write the stream to a byte array for output 380 // Write the stream to a byte array for output
387 data = imgstream.ToArray(); 381 data = imgstream.ToArray();
382 }
383 else
384 m_log.WarnFormat("[GETTEXTURE]: No such codec {0}", format);
388 } 385 }
389 else
390 m_log.WarnFormat("[GETTEXTURE]: No such codec {0}", format);
391
392 } 386 }
393 } 387 }
394 catch (Exception e) 388 catch (Exception e)
@@ -405,11 +399,10 @@ namespace OpenSim.Capabilities.Handlers
405 if (image != null) 399 if (image != null)
406 image.Dispose(); 400 image.Dispose();
407 401
402 if(managedImage != null)
403 managedImage.Clear();
408 if (imgstream != null) 404 if (imgstream != null)
409 {
410 imgstream.Close();
411 imgstream.Dispose(); 405 imgstream.Dispose();
412 }
413 } 406 }
414 407
415 return data; 408 return data;
@@ -428,4 +421,4 @@ namespace OpenSim.Capabilities.Handlers
428 return null; 421 return null;
429 } 422 }
430 } 423 }
431} \ No newline at end of file 424}
diff --git a/OpenSim/Capabilities/Handlers/GetTexture/GetTextureRobustHandler.cs b/OpenSim/Capabilities/Handlers/GetTexture/GetTextureRobustHandler.cs
new file mode 100644
index 0000000..0685c5e
--- /dev/null
+++ b/OpenSim/Capabilities/Handlers/GetTexture/GetTextureRobustHandler.cs
@@ -0,0 +1,394 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections;
30using System.Collections.Specialized;
31using System.Drawing;
32using System.Drawing.Imaging;
33using System.Reflection;
34using System.IO;
35using System.Web;
36using log4net;
37using Nini.Config;
38using OpenMetaverse;
39using OpenMetaverse.StructuredData;
40using OpenMetaverse.Imaging;
41using OpenSim.Framework;
42using OpenSim.Framework.Servers;
43using OpenSim.Framework.Servers.HttpServer;
44using OpenSim.Region.Framework.Interfaces;
45using OpenSim.Services.Interfaces;
46using Caps = OpenSim.Framework.Capabilities.Caps;
47
48namespace OpenSim.Capabilities.Handlers
49{
50 public class GetTextureRobustHandler : BaseStreamHandler
51 {
52 private static readonly ILog m_log =
53 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
54 private IAssetService m_assetService;
55
56 public const string DefaultFormat = "x-j2c";
57
58 // TODO: Change this to a config option
59 private string m_RedirectURL = null;
60
61 public GetTextureRobustHandler(string path, IAssetService assService, string name, string description, string redirectURL)
62 : base("GET", path, name, description)
63 {
64 m_assetService = assService;
65 m_RedirectURL = redirectURL;
66 if (m_RedirectURL != null && !m_RedirectURL.EndsWith("/"))
67 m_RedirectURL += "/";
68 }
69
70 protected override byte[] ProcessRequest(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
71 {
72 // Try to parse the texture ID from the request URL
73 NameValueCollection query = HttpUtility.ParseQueryString(httpRequest.Url.Query);
74 string textureStr = query.GetOne("texture_id");
75 string format = query.GetOne("format");
76
77 //m_log.DebugFormat("[GETTEXTURE]: called {0}", textureStr);
78
79 if (m_assetService == null)
80 {
81 m_log.Error("[GETTEXTURE]: Cannot fetch texture " + textureStr + " without an asset service");
82 httpResponse.StatusCode = (int)System.Net.HttpStatusCode.NotFound;
83 return null;
84 }
85
86 UUID textureID;
87 if (!String.IsNullOrEmpty(textureStr) && UUID.TryParse(textureStr, out textureID))
88 {
89// m_log.DebugFormat("[GETTEXTURE]: Received request for texture id {0}", textureID);
90
91 string[] formats;
92 if (!string.IsNullOrEmpty(format))
93 {
94 formats = new string[1] { format.ToLower() };
95 }
96 else
97 {
98 formats = WebUtil.GetPreferredImageTypes(httpRequest.Headers.Get("Accept"));
99 if (formats.Length == 0)
100 formats = new string[1] { DefaultFormat }; // default
101
102 }
103 // OK, we have an array with preferred formats, possibly with only one entry
104
105 httpResponse.StatusCode = (int)System.Net.HttpStatusCode.NotFound;
106 foreach (string f in formats)
107 {
108 if (FetchTexture(httpRequest, httpResponse, textureID, f))
109 break;
110 }
111 }
112 else
113 {
114 m_log.Warn("[GETTEXTURE]: Failed to parse a texture_id from GetTexture request: " + httpRequest.Url);
115 }
116
117// m_log.DebugFormat(
118// "[GETTEXTURE]: For texture {0} sending back response {1}, data length {2}",
119// textureID, httpResponse.StatusCode, httpResponse.ContentLength);
120
121 return null;
122 }
123
124 /// <summary>
125 ///
126 /// </summary>
127 /// <param name="httpRequest"></param>
128 /// <param name="httpResponse"></param>
129 /// <param name="textureID"></param>
130 /// <param name="format"></param>
131 /// <returns>False for "caller try another codec"; true otherwise</returns>
132 private bool FetchTexture(IOSHttpRequest httpRequest, IOSHttpResponse httpResponse, UUID textureID, string format)
133 {
134 // m_log.DebugFormat("[GETTEXTURE]: {0} with requested format {1}", textureID, format);
135 AssetBase texture;
136
137 if(!String.IsNullOrEmpty(m_RedirectURL))
138 {
139 string textureUrl = m_RedirectURL + "?texture_id=" + textureID.ToString();
140 m_log.Debug("[GETTEXTURE]: Redirecting texture request to " + textureUrl);
141 httpResponse.StatusCode = (int)OSHttpStatusCode.RedirectMovedPermanently;
142 httpResponse.RedirectLocation = textureUrl;
143 return true;
144 }
145 else // no redirect
146 {
147 texture = m_assetService.Get(textureID.ToString());
148 if(texture != null)
149 {
150 if(texture.Type != (sbyte)AssetType.Texture)
151 {
152 httpResponse.StatusCode = (int)System.Net.HttpStatusCode.NotFound;
153 return true;
154 }
155 if(format == DefaultFormat)
156 {
157 WriteTextureData(httpRequest, httpResponse, texture, format);
158 return true;
159 }
160 else
161 {
162 AssetBase newTexture = new AssetBase(texture.ID + "-" + format, texture.Name, (sbyte)AssetType.Texture, texture.Metadata.CreatorID);
163 newTexture.Data = ConvertTextureData(texture, format);
164 if(newTexture.Data.Length == 0)
165 return false; // !!! Caller try another codec, please!
166
167 newTexture.Flags = AssetFlags.Collectable;
168 newTexture.Temporary = true;
169 newTexture.Local = true;
170 WriteTextureData(httpRequest, httpResponse, newTexture, format);
171 return true;
172 }
173 }
174 }
175
176 // not found
177 // m_log.Warn("[GETTEXTURE]: Texture " + textureID + " not found");
178 httpResponse.StatusCode = (int)System.Net.HttpStatusCode.NotFound;
179 return true;
180 }
181
182 private void WriteTextureData(IOSHttpRequest request, IOSHttpResponse response, AssetBase texture, string format)
183 {
184 string range = request.Headers.GetOne("Range");
185
186 if (!String.IsNullOrEmpty(range)) // JP2's only
187 {
188 // Range request
189 int start, end;
190 if (TryParseRange(range, out start, out end))
191 {
192 // Before clamping start make sure we can satisfy it in order to avoid
193 // sending back the last byte instead of an error status
194 if (start >= texture.Data.Length)
195 {
196// m_log.DebugFormat(
197// "[GETTEXTURE]: Client requested range for texture {0} starting at {1} but texture has end of {2}",
198// texture.ID, start, texture.Data.Length);
199
200 // Stricly speaking, as per http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html, we should be sending back
201 // Requested Range Not Satisfiable (416) here. However, it appears that at least recent implementations
202 // of the Linden Lab viewer (3.2.1 and 3.3.4 and probably earlier), a viewer that has previously
203 // received a very small texture may attempt to fetch bytes from the server past the
204 // range of data that it received originally. Whether this happens appears to depend on whether
205 // the viewer's estimation of how large a request it needs to make for certain discard levels
206 // (http://wiki.secondlife.com/wiki/Image_System#Discard_Level_and_Mip_Mapping), chiefly discard
207 // level 2. If this estimate is greater than the total texture size, returning a RequestedRangeNotSatisfiable
208 // here will cause the viewer to treat the texture as bad and never display the full resolution
209 // However, if we return PartialContent (or OK) instead, the viewer will display that resolution.
210
211// response.StatusCode = (int)System.Net.HttpStatusCode.RequestedRangeNotSatisfiable;
212// response.AddHeader("Content-Range", String.Format("bytes */{0}", texture.Data.Length));
213// response.StatusCode = (int)System.Net.HttpStatusCode.OK;
214 response.StatusCode = (int)System.Net.HttpStatusCode.PartialContent;
215 response.ContentType = texture.Metadata.ContentType;
216 }
217 else
218 {
219 // Handle the case where no second range value was given. This is equivalent to requesting
220 // the rest of the entity.
221 if (end == -1)
222 end = int.MaxValue;
223
224 end = Utils.Clamp(end, 0, texture.Data.Length - 1);
225 start = Utils.Clamp(start, 0, end);
226 int len = end - start + 1;
227
228// m_log.Debug("Serving " + start + " to " + end + " of " + texture.Data.Length + " bytes for texture " + texture.ID);
229
230 // Always return PartialContent, even if the range covered the entire data length
231 // We were accidentally sending back 404 before in this situation
232 // https://issues.apache.org/bugzilla/show_bug.cgi?id=51878 supports sending 206 even if the
233 // entire range is requested, and viewer 3.2.2 (and very probably earlier) seems fine with this.
234 //
235 // We also do not want to send back OK even if the whole range was satisfiable since this causes
236 // HTTP textures on at least Imprudence 1.4.0-beta2 to never display the final texture quality.
237// if (end > maxEnd)
238// response.StatusCode = (int)System.Net.HttpStatusCode.OK;
239// else
240 response.StatusCode = (int)System.Net.HttpStatusCode.PartialContent;
241
242 response.ContentLength = len;
243 response.ContentType = texture.Metadata.ContentType;
244 response.AddHeader("Content-Range", String.Format("bytes {0}-{1}/{2}", start, end, texture.Data.Length));
245
246 response.Body.Write(texture.Data, start, len);
247 }
248 }
249 else
250 {
251 m_log.Warn("[GETTEXTURE]: Malformed Range header: " + range);
252 response.StatusCode = (int)System.Net.HttpStatusCode.BadRequest;
253 }
254 }
255 else // JP2's or other formats
256 {
257 // Full content request
258 response.StatusCode = (int)System.Net.HttpStatusCode.OK;
259 response.ContentLength = texture.Data.Length;
260 if (format == DefaultFormat)
261 response.ContentType = texture.Metadata.ContentType;
262 else
263 response.ContentType = "image/" + format;
264 response.Body.Write(texture.Data, 0, texture.Data.Length);
265 }
266
267// if (response.StatusCode < 200 || response.StatusCode > 299)
268// m_log.WarnFormat(
269// "[GETTEXTURE]: For texture {0} requested range {1} responded {2} with content length {3} (actual {4})",
270// texture.FullID, range, response.StatusCode, response.ContentLength, texture.Data.Length);
271// else
272// m_log.DebugFormat(
273// "[GETTEXTURE]: For texture {0} requested range {1} responded {2} with content length {3} (actual {4})",
274// texture.FullID, range, response.StatusCode, response.ContentLength, texture.Data.Length);
275 }
276
277 /// <summary>
278 /// Parse a range header.
279 /// </summary>
280 /// <remarks>
281 /// As per http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html,
282 /// this obeys range headers with two values (e.g. 533-4165) and no second value (e.g. 533-).
283 /// Where there is no value, -1 is returned.
284 /// FIXME: Need to cover the case where only a second value is specified (e.g. -4165), probably by returning -1
285 /// for start.</remarks>
286 /// <returns></returns>
287 /// <param name='header'></param>
288 /// <param name='start'>Start of the range. Undefined if this was not a number.</param>
289 /// <param name='end'>End of the range. Will be -1 if no end specified. Undefined if there was a raw string but this was not a number.</param>
290 private bool TryParseRange(string header, out int start, out int end)
291 {
292 start = end = 0;
293
294 if (header.StartsWith("bytes="))
295 {
296 string[] rangeValues = header.Substring(6).Split('-');
297
298 if (rangeValues.Length == 2)
299 {
300 if (!Int32.TryParse(rangeValues[0], out start))
301 return false;
302
303 string rawEnd = rangeValues[1];
304
305 if (rawEnd == "")
306 {
307 end = -1;
308 return true;
309 }
310 else if (Int32.TryParse(rawEnd, out end))
311 {
312 return true;
313 }
314 }
315 }
316
317 start = end = 0;
318 return false;
319 }
320
321 private byte[] ConvertTextureData(AssetBase texture, string format)
322 {
323 m_log.DebugFormat("[GETTEXTURE]: Converting texture {0} to {1}", texture.ID, format);
324 byte[] data = new byte[0];
325
326 MemoryStream imgstream = new MemoryStream();
327 Bitmap mTexture = null;
328 ManagedImage managedImage = null;
329 Image image = null;
330
331 try
332 {
333 // Taking our jpeg2000 data, decoding it, then saving it to a byte array with regular data
334 // Decode image to System.Drawing.Image
335 if (OpenJPEG.DecodeToImage(texture.Data, out managedImage, out image) && image != null)
336 {
337 // Save to bitmap
338 mTexture = new Bitmap(image);
339
340 using(EncoderParameters myEncoderParameters = new EncoderParameters())
341 {
342 myEncoderParameters.Param[0] = new EncoderParameter(Encoder.Quality,95L);
343
344 // Save bitmap to stream
345 ImageCodecInfo codec = GetEncoderInfo("image/" + format);
346 if (codec != null)
347 {
348 mTexture.Save(imgstream, codec, myEncoderParameters);
349 // Write the stream to a byte array for output
350 data = imgstream.ToArray();
351 }
352 else
353 m_log.WarnFormat("[GETTEXTURE]: No such codec {0}", format);
354 }
355 }
356 }
357 catch (Exception e)
358 {
359 m_log.WarnFormat("[GETTEXTURE]: Unable to convert texture {0} to {1}: {2}", texture.ID, format, e.Message);
360 }
361 finally
362 {
363 // Reclaim memory, these are unmanaged resources
364 // If we encountered an exception, one or more of these will be null
365 if (mTexture != null)
366 mTexture.Dispose();
367
368 if (image != null)
369 image.Dispose();
370
371 if(managedImage != null)
372 managedImage.Clear();
373
374 if (imgstream != null)
375 imgstream.Dispose();
376 }
377
378 return data;
379 }
380
381 // From msdn
382 private static ImageCodecInfo GetEncoderInfo(String mimeType)
383 {
384 ImageCodecInfo[] encoders;
385 encoders = ImageCodecInfo.GetImageEncoders();
386 for (int j = 0; j < encoders.Length; ++j)
387 {
388 if (encoders[j].MimeType == mimeType)
389 return encoders[j];
390 }
391 return null;
392 }
393 }
394}
diff --git a/OpenSim/Capabilities/Handlers/GetTexture/GetTextureServerConnector.cs b/OpenSim/Capabilities/Handlers/GetTexture/GetTextureServerConnector.cs
index fa0b228..479cebb 100644
--- a/OpenSim/Capabilities/Handlers/GetTexture/GetTextureServerConnector.cs
+++ b/OpenSim/Capabilities/Handlers/GetTexture/GetTextureServerConnector.cs
@@ -33,6 +33,7 @@ using OpenSim.Framework.Servers.HttpServer;
33using OpenSim.Server.Handlers.Base; 33using OpenSim.Server.Handlers.Base;
34using OpenMetaverse; 34using OpenMetaverse;
35 35
36
36namespace OpenSim.Capabilities.Handlers 37namespace OpenSim.Capabilities.Handlers
37{ 38{
38 public class GetTextureServerConnector : ServiceConnector 39 public class GetTextureServerConnector : ServiceConnector
@@ -65,7 +66,8 @@ namespace OpenSim.Capabilities.Handlers
65 string rurl = serverConfig.GetString("GetTextureRedirectURL"); 66 string rurl = serverConfig.GetString("GetTextureRedirectURL");
66 ; 67 ;
67 server.AddStreamHandler( 68 server.AddStreamHandler(
68 new GetTextureHandler("/CAPS/GetTexture/" /*+ UUID.Random() */, m_AssetService, "GetTexture", null, rurl)); 69 new GetTextureRobustHandler("/CAPS/GetTexture/", m_AssetService, "GetTexture", null, rurl));
69 } 70 }
70 } 71 }
71} \ No newline at end of file 72}
73
diff --git a/OpenSim/Capabilities/Handlers/GetTexture/Tests/GetTextureHandlerTests.cs b/OpenSim/Capabilities/Handlers/GetTexture/Tests/GetTextureHandlerTests.cs
index e5d9618..61aa689 100644
--- a/OpenSim/Capabilities/Handlers/GetTexture/Tests/GetTextureHandlerTests.cs
+++ b/OpenSim/Capabilities/Handlers/GetTexture/Tests/GetTextureHandlerTests.cs
@@ -38,6 +38,7 @@ using OpenSim.Framework.Servers.HttpServer;
38using OpenSim.Region.Framework.Scenes; 38using OpenSim.Region.Framework.Scenes;
39using OpenSim.Tests.Common; 39using OpenSim.Tests.Common;
40 40
41/*
41namespace OpenSim.Capabilities.Handlers.GetTexture.Tests 42namespace OpenSim.Capabilities.Handlers.GetTexture.Tests
42{ 43{
43 [TestFixture] 44 [TestFixture]
@@ -59,4 +60,5 @@ namespace OpenSim.Capabilities.Handlers.GetTexture.Tests
59 Assert.That(resp.StatusCode, Is.EqualTo((int)System.Net.HttpStatusCode.NotFound)); 60 Assert.That(resp.StatusCode, Is.EqualTo((int)System.Net.HttpStatusCode.NotFound));
60 } 61 }
61 } 62 }
62} \ No newline at end of file 63}
64*/
diff --git a/OpenSim/Capabilities/Handlers/Properties/AssemblyInfo.cs b/OpenSim/Capabilities/Handlers/Properties/AssemblyInfo.cs
index 1a6d04f..387b3de 100644
--- a/OpenSim/Capabilities/Handlers/Properties/AssemblyInfo.cs
+++ b/OpenSim/Capabilities/Handlers/Properties/AssemblyInfo.cs
@@ -2,7 +2,7 @@
2using System.Runtime.CompilerServices; 2using System.Runtime.CompilerServices;
3using System.Runtime.InteropServices; 3using System.Runtime.InteropServices;
4 4
5// General Information about an assembly is controlled through the following 5// General Information about an assembly is controlled through the following
6// set of attributes. Change these attribute values to modify the information 6// set of attributes. Change these attribute values to modify the information
7// associated with an assembly. 7// associated with an assembly.
8[assembly: AssemblyTitle("OpenSim.Capabilities.Handlers")] 8[assembly: AssemblyTitle("OpenSim.Capabilities.Handlers")]
@@ -14,8 +14,8 @@ using System.Runtime.InteropServices;
14[assembly: AssemblyTrademark("")] 14[assembly: AssemblyTrademark("")]
15[assembly: AssemblyCulture("")] 15[assembly: AssemblyCulture("")]
16 16
17// Setting ComVisible to false makes the types in this assembly not visible 17// Setting ComVisible to false makes the types in this assembly not visible
18// to COM components. If you need to access a type in this assembly from 18// to COM components. If you need to access a type in this assembly from
19// COM, set the ComVisible attribute to true on that type. 19// COM, set the ComVisible attribute to true on that type.
20[assembly: ComVisible(false)] 20[assembly: ComVisible(false)]
21 21
@@ -25,9 +25,9 @@ using System.Runtime.InteropServices;
25// Version information for an assembly consists of the following four values: 25// Version information for an assembly consists of the following four values:
26// 26//
27// Major Version 27// Major Version
28// Minor Version 28// Minor Version
29// Build Number 29// Build Number
30// Revision 30// Revision
31// 31//
32[assembly: AssemblyVersion("0.8.3.*")] 32[assembly: AssemblyVersion(OpenSim.VersionInfo.AssemblyVersionNumber)]
33 33
diff --git a/OpenSim/Capabilities/Handlers/UploadBakedTexture/UploadBakedTextureHandler.cs b/OpenSim/Capabilities/Handlers/UploadBakedTexture/UploadBakedTextureHandler.cs
index 8849a59..48274c1 100644
--- a/OpenSim/Capabilities/Handlers/UploadBakedTexture/UploadBakedTextureHandler.cs
+++ b/OpenSim/Capabilities/Handlers/UploadBakedTexture/UploadBakedTextureHandler.cs
@@ -26,23 +26,12 @@
26 */ 26 */
27 27
28using System; 28using System;
29using System.Collections;
30using System.Collections.Specialized;
31using System.Drawing;
32using System.Drawing.Imaging;
33using System.Reflection; 29using System.Reflection;
34using System.IO;
35using System.Web;
36using log4net; 30using log4net;
37using Nini.Config;
38using OpenMetaverse; 31using OpenMetaverse;
39using OpenMetaverse.StructuredData;
40using OpenMetaverse.Imaging;
41using OpenSim.Framework; 32using OpenSim.Framework;
42using OpenSim.Framework.Capabilities; 33using OpenSim.Framework.Capabilities;
43using OpenSim.Framework.Servers;
44using OpenSim.Framework.Servers.HttpServer; 34using OpenSim.Framework.Servers.HttpServer;
45using OpenSim.Region.Framework.Interfaces;
46using OpenSim.Services.Interfaces; 35using OpenSim.Services.Interfaces;
47using Caps = OpenSim.Framework.Capabilities.Caps; 36using Caps = OpenSim.Framework.Capabilities.Caps;
48 37
@@ -50,17 +39,16 @@ namespace OpenSim.Capabilities.Handlers
50{ 39{
51 public class UploadBakedTextureHandler 40 public class UploadBakedTextureHandler
52 { 41 {
42
53 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 43 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
54 44
55 private Caps m_HostCapsObj; 45 private Caps m_HostCapsObj;
56 private IAssetService m_assetService; 46 private IAssetService m_assetService;
57 private bool m_persistBakedTextures;
58 47
59 public UploadBakedTextureHandler(Caps caps, IAssetService assetService, bool persistBakedTextures) 48 public UploadBakedTextureHandler(Caps caps, IAssetService assetService)
60 { 49 {
61 m_HostCapsObj = caps; 50 m_HostCapsObj = caps;
62 m_assetService = assetService; 51 m_assetService = assetService;
63 m_persistBakedTextures = persistBakedTextures;
64 } 52 }
65 53
66 /// <summary> 54 /// <summary>
@@ -81,7 +69,7 @@ namespace OpenSim.Capabilities.Handlers
81 string uploaderPath = Util.RandomClass.Next(5000, 8000).ToString("0000"); 69 string uploaderPath = Util.RandomClass.Next(5000, 8000).ToString("0000");
82 70
83 BakedTextureUploader uploader = 71 BakedTextureUploader uploader =
84 new BakedTextureUploader(capsBase + uploaderPath, m_HostCapsObj.HttpListener); 72 new BakedTextureUploader(capsBase + uploaderPath, m_HostCapsObj.HttpListener, m_HostCapsObj.AgentID);
85 uploader.OnUpLoad += BakedTextureUploaded; 73 uploader.OnUpLoad += BakedTextureUploaded;
86 74
87 m_HostCapsObj.HttpListener.AddStreamHandler( 75 m_HostCapsObj.HttpListener.AddStreamHandler(
@@ -117,13 +105,13 @@ namespace OpenSim.Capabilities.Handlers
117 /// <param name="data"></param> 105 /// <param name="data"></param>
118 private void BakedTextureUploaded(UUID assetID, byte[] data) 106 private void BakedTextureUploaded(UUID assetID, byte[] data)
119 { 107 {
120// m_log.DebugFormat("[UPLOAD BAKED TEXTURE HANDLER]: Received baked texture {0}", assetID.ToString()); 108 m_log.DebugFormat("[UPLOAD BAKED TEXTURE HANDLER]: Received baked texture {0}", assetID.ToString());
121 109
122 AssetBase asset; 110 AssetBase asset;
123 asset = new AssetBase(assetID, "Baked Texture", (sbyte)AssetType.Texture, m_HostCapsObj.AgentID.ToString()); 111 asset = new AssetBase(assetID, "Baked Texture", (sbyte)AssetType.Texture, m_HostCapsObj.AgentID.ToString());
124 asset.Data = data; 112 asset.Data = data;
125 asset.Temporary = true; 113 asset.Temporary = true;
126 asset.Local = !m_persistBakedTextures; // Local assets aren't persisted, non-local are 114 asset.Local = true;
127 m_assetService.Store(asset); 115 m_assetService.Store(asset);
128 } 116 }
129 } 117 }
@@ -137,12 +125,14 @@ namespace OpenSim.Capabilities.Handlers
137 private string uploaderPath = String.Empty; 125 private string uploaderPath = String.Empty;
138 private UUID newAssetID; 126 private UUID newAssetID;
139 private IHttpServer httpListener; 127 private IHttpServer httpListener;
128 private UUID AgentId = UUID.Zero;
140 129
141 public BakedTextureUploader(string path, IHttpServer httpServer) 130 public BakedTextureUploader(string path, IHttpServer httpServer, UUID uUID)
142 { 131 {
143 newAssetID = UUID.Random(); 132 newAssetID = UUID.Random();
144 uploaderPath = path; 133 uploaderPath = path;
145 httpListener = httpServer; 134 httpListener = httpServer;
135 AgentId = uUID;
146 // m_log.InfoFormat("[CAPS] baked texture upload starting for {0}",newAssetID); 136 // m_log.InfoFormat("[CAPS] baked texture upload starting for {0}",newAssetID);
147 } 137 }
148 138
diff --git a/OpenSim/Capabilities/Handlers/UploadBakedTexture/UploadBakedTextureServerConnector.cs b/OpenSim/Capabilities/Handlers/UploadBakedTexture/UploadBakedTextureServerConnector.cs
index 10ea8ee..fd484ba 100644
--- a/OpenSim/Capabilities/Handlers/UploadBakedTexture/UploadBakedTextureServerConnector.cs
+++ b/OpenSim/Capabilities/Handlers/UploadBakedTexture/UploadBakedTextureServerConnector.cs
@@ -67,7 +67,7 @@ namespace OpenSim.Capabilities.Handlers
67 server.AddStreamHandler(new RestStreamHandler( 67 server.AddStreamHandler(new RestStreamHandler(
68 "POST", 68 "POST",
69 "/CAPS/UploadBakedTexture/", 69 "/CAPS/UploadBakedTexture/",
70 new UploadBakedTextureHandler(caps, m_AssetService, true).UploadBakedTexture, 70 new UploadBakedTextureHandler(caps, m_AssetService).UploadBakedTexture,
71 "UploadBakedTexture", 71 "UploadBakedTexture",
72 "Upload Baked Texture Capability")); 72 "Upload Baked Texture Capability"));
73 73
diff --git a/OpenSim/Capabilities/LLSD.cs b/OpenSim/Capabilities/LLSD.cs
index c59cede..fc41113 100644
--- a/OpenSim/Capabilities/LLSD.cs
+++ b/OpenSim/Capabilities/LLSD.cs
@@ -83,6 +83,8 @@ namespace OpenSim.Framework.Capabilities
83 { 83 {
84 using (XmlTextReader reader = new XmlTextReader(st)) 84 using (XmlTextReader reader = new XmlTextReader(st))
85 { 85 {
86 reader.ProhibitDtd = true;
87
86 reader.Read(); 88 reader.Read();
87 SkipWS(reader); 89 SkipWS(reader);
88 90
@@ -566,7 +568,7 @@ namespace OpenSim.Framework.Capabilities
566 endPos = FindEnd(llsd, 1); 568 endPos = FindEnd(llsd, 1);
567 569
568 if (Double.TryParse(llsd.Substring(1, endPos - 1), NumberStyles.Float, 570 if (Double.TryParse(llsd.Substring(1, endPos - 1), NumberStyles.Float,
569 Utils.EnUsCulture.NumberFormat, out value)) 571 Culture.NumberFormatInfo, out value))
570 return value; 572 return value;
571 else 573 else
572 throw new LLSDParseException("Failed to parse double value type"); 574 throw new LLSDParseException("Failed to parse double value type");
diff --git a/OpenSim/Capabilities/LLSDAssetUploadComplete.cs b/OpenSim/Capabilities/LLSDAssetUploadComplete.cs
index ab6cee5..476cf6e 100644
--- a/OpenSim/Capabilities/LLSDAssetUploadComplete.cs
+++ b/OpenSim/Capabilities/LLSDAssetUploadComplete.cs
@@ -30,13 +30,20 @@ using OpenMetaverse;
30 30
31namespace OpenSim.Framework.Capabilities 31namespace OpenSim.Framework.Capabilities
32{ 32{
33
33 [LLSDType("MAP")] 34 [LLSDType("MAP")]
34 public class LLSDAssetUploadComplete 35 public class LLSDAssetUploadComplete
35 { 36 {
36 public string new_asset = String.Empty; 37 public string new_asset = String.Empty;
37 public UUID new_inventory_item = UUID.Zero; 38 public UUID new_inventory_item = UUID.Zero;
39// public UUID new_texture_folder_id = UUID.Zero;
38 public string state = String.Empty; 40 public string state = String.Empty;
41 public LLSDAssetUploadError error = null;
39 //public bool success = false; 42 //public bool success = false;
43 public int new_next_owner_mask = 0;
44 public int new_group_mask = 0;
45 public int new_everyone_mask = 0;
46 public int inventory_item_flags = 0;
40 47
41 public LLSDAssetUploadComplete() 48 public LLSDAssetUploadComplete()
42 { 49 {
diff --git a/OpenSim/Capabilities/LLSDAssetUploadRequest.cs b/OpenSim/Capabilities/LLSDAssetUploadRequest.cs
index 6e66f0a..6779cc1 100644
--- a/OpenSim/Capabilities/LLSDAssetUploadRequest.cs
+++ b/OpenSim/Capabilities/LLSDAssetUploadRequest.cs
@@ -31,14 +31,27 @@ using OpenMetaverse;
31namespace OpenSim.Framework.Capabilities 31namespace OpenSim.Framework.Capabilities
32{ 32{
33 [OSDMap] 33 [OSDMap]
34 public class LLSDAssetResource
35 {
36 public OSDArray instance_list = new OSDArray();
37 public OSDArray texture_list = new OSDArray();
38 public OSDArray mesh_list = new OSDArray();
39 public string metric = String.Empty;
40 }
41
42 [OSDMap]
34 public class LLSDAssetUploadRequest 43 public class LLSDAssetUploadRequest
35 { 44 {
36 public string asset_type = String.Empty; 45 public string asset_type = String.Empty;
37 public string description = String.Empty; 46 public string description = String.Empty;
38 public UUID folder_id = UUID.Zero; 47 public UUID folder_id = UUID.Zero;
48 public UUID texture_folder_id = UUID.Zero;
49 public int next_owner_mask = 0;
50 public int group_mask = 0;
51 public int everyone_mask = 0;
39 public string inventory_type = String.Empty; 52 public string inventory_type = String.Empty;
40 public string name = String.Empty; 53 public string name = String.Empty;
41 54 public LLSDAssetResource asset_resources = new LLSDAssetResource();
42 public LLSDAssetUploadRequest() 55 public LLSDAssetUploadRequest()
43 { 56 {
44 } 57 }
diff --git a/OpenSim/Capabilities/LLSDAssetUploadResponse.cs b/OpenSim/Capabilities/LLSDAssetUploadResponse.cs
index 0d6f7f9..97491e3 100644
--- a/OpenSim/Capabilities/LLSDAssetUploadResponse.cs
+++ b/OpenSim/Capabilities/LLSDAssetUploadResponse.cs
@@ -26,20 +26,51 @@
26 */ 26 */
27 27
28using System; 28using System;
29using OpenMetaverse;
29 30
30namespace OpenSim.Framework.Capabilities 31namespace OpenSim.Framework.Capabilities
31{ 32{
32 [OSDMap] 33 [OSDMap]
34 public class LLSDAssetUploadError
35 {
36 public string message = String.Empty;
37 public UUID identifier = UUID.Zero;
38 }
39
40 [OSDMap]
41 public class LLSDAssetUploadResponsePricebrkDown
42 {
43 public int mesh_streaming;
44 public int mesh_physics;
45 public int mesh_instance;
46 public int texture;
47 public int model;
48 }
49
50 [OSDMap]
51 public class LLSDAssetUploadResponseData
52 {
53 public double resource_cost;
54 public double model_streaming_cost;
55 public double simulation_cost;
56 public double physics_cost;
57 public LLSDAssetUploadResponsePricebrkDown upload_price_breakdown = new LLSDAssetUploadResponsePricebrkDown();
58 }
59
60 [OSDMap]
33 public class LLSDAssetUploadResponse 61 public class LLSDAssetUploadResponse
34 { 62 {
35 public string uploader = String.Empty; 63 public string uploader = String.Empty;
36 public string state = String.Empty; 64 public string state = String.Empty;
37 65 public int upload_price = 0;
66 public LLSDAssetUploadResponseData data = null;
67 public LLSDAssetUploadError error = null;
38 public LLSDAssetUploadResponse() 68 public LLSDAssetUploadResponse()
39 { 69 {
40 } 70 }
41 } 71 }
42 72
73
43 [OSDMap] 74 [OSDMap]
44 public class LLSDNewFileAngentInventoryVariablePriceReplyResponse 75 public class LLSDNewFileAngentInventoryVariablePriceReplyResponse
45 { 76 {
@@ -47,7 +78,7 @@ namespace OpenSim.Framework.Capabilities
47 public string state; 78 public string state;
48 public int upload_price; 79 public int upload_price;
49 public string rsvp; 80 public string rsvp;
50 81
51 public LLSDNewFileAngentInventoryVariablePriceReplyResponse() 82 public LLSDNewFileAngentInventoryVariablePriceReplyResponse()
52 { 83 {
53 state = "confirm_upload"; 84 state = "confirm_upload";
diff --git a/OpenSim/Capabilities/LLSDAvatarPicker.cs b/OpenSim/Capabilities/LLSDAvatarPicker.cs
index d0b3f3a..12e892c 100644
--- a/OpenSim/Capabilities/LLSDAvatarPicker.cs
+++ b/OpenSim/Capabilities/LLSDAvatarPicker.cs
@@ -42,7 +42,7 @@ namespace OpenSim.Framework.Capabilities
42 { 42 {
43 public string username; 43 public string username;
44 public string display_name; 44 public string display_name;
45 //'display_name_next_update':d"1970-01-01T00:00:00Z" 45 //'display_name_next_update':d"1970-01-01T00:00:00Z"
46 public string legacy_first_name; 46 public string legacy_first_name;
47 public string legacy_last_name; 47 public string legacy_last_name;
48 public UUID id; 48 public UUID id;
diff --git a/OpenSim/Capabilities/LLSDHelpers.cs b/OpenSim/Capabilities/LLSDHelpers.cs
index 8f1a40e..d582267 100644
--- a/OpenSim/Capabilities/LLSDHelpers.cs
+++ b/OpenSim/Capabilities/LLSDHelpers.cs
@@ -157,6 +157,11 @@ namespace OpenSim.Framework.Capabilities
157 // the LLSD map/array types in the array need to be deserialised 157 // the LLSD map/array types in the array need to be deserialised
158 // but first we need to know the right class to deserialise them into. 158 // but first we need to know the right class to deserialise them into.
159 } 159 }
160 else if(enumerator.Value is Boolean && field.FieldType == typeof(int) )
161 {
162 int i = (bool)enumerator.Value ? 1 : 0;
163 field.SetValue(obj, (object)i);
164 }
160 else 165 else
161 { 166 {
162 field.SetValue(obj, enumerator.Value); 167 field.SetValue(obj, enumerator.Value);
diff --git a/OpenSim/Capabilities/LLSDInventoryItem.cs b/OpenSim/Capabilities/LLSDInventoryItem.cs
index 958e807..460a215 100644
--- a/OpenSim/Capabilities/LLSDInventoryItem.cs
+++ b/OpenSim/Capabilities/LLSDInventoryItem.cs
@@ -87,12 +87,12 @@ namespace OpenSim.Framework.Capabilities
87 [OSDMap] 87 [OSDMap]
88 public class LLSDInventoryFolderContents 88 public class LLSDInventoryFolderContents
89 { 89 {
90 public UUID agent_id; 90 public UUID agent_id;
91 public int descendents; 91 public int descendents;
92 public UUID folder_id; 92 public UUID folder_id;
93 public OSDArray categories = new OSDArray(); 93 public OSDArray categories = new OSDArray();
94 public OSDArray items = new OSDArray(); 94 public OSDArray items = new OSDArray();
95 public UUID owner_id; 95 public UUID owner_id;
96 public int version; 96 public int version;
97 } 97 }
98 98
diff --git a/OpenSim/Capabilities/LLSDStreamHandler.cs b/OpenSim/Capabilities/LLSDStreamHandler.cs
index 4fa1153..4f1b10a 100644
--- a/OpenSim/Capabilities/LLSDStreamHandler.cs
+++ b/OpenSim/Capabilities/LLSDStreamHandler.cs
@@ -61,6 +61,9 @@ namespace OpenSim.Framework.Capabilities
61 // OpenMetaverse.StructuredData.LLSDParser.DeserializeXml(new XmlTextReader(request)); 61 // OpenMetaverse.StructuredData.LLSDParser.DeserializeXml(new XmlTextReader(request));
62 62
63 Hashtable hash = (Hashtable) LLSD.LLSDDeserialize(request); 63 Hashtable hash = (Hashtable) LLSD.LLSDDeserialize(request);
64 if(hash == null)
65 return new byte[0];
66
64 TRequest llsdRequest = new TRequest(); 67 TRequest llsdRequest = new TRequest();
65 LLSDHelpers.DeserialiseOSDMap(hash, llsdRequest); 68 LLSDHelpers.DeserialiseOSDMap(hash, llsdRequest);
66 69
diff --git a/OpenSim/Capabilities/Properties/AssemblyInfo.cs b/OpenSim/Capabilities/Properties/AssemblyInfo.cs
index f8a9dae..72a5240 100644
--- a/OpenSim/Capabilities/Properties/AssemblyInfo.cs
+++ b/OpenSim/Capabilities/Properties/AssemblyInfo.cs
@@ -2,7 +2,7 @@
2using System.Runtime.CompilerServices; 2using System.Runtime.CompilerServices;
3using System.Runtime.InteropServices; 3using System.Runtime.InteropServices;
4 4
5// General Information about an assembly is controlled through the following 5// General Information about an assembly is controlled through the following
6// set of attributes. Change these attribute values to modify the information 6// set of attributes. Change these attribute values to modify the information
7// associated with an assembly. 7// associated with an assembly.
8[assembly: AssemblyTitle("OpenSim.Capabilities")] 8[assembly: AssemblyTitle("OpenSim.Capabilities")]
@@ -14,8 +14,8 @@ using System.Runtime.InteropServices;
14[assembly: AssemblyTrademark("")] 14[assembly: AssemblyTrademark("")]
15[assembly: AssemblyCulture("")] 15[assembly: AssemblyCulture("")]
16 16
17// Setting ComVisible to false makes the types in this assembly not visible 17// Setting ComVisible to false makes the types in this assembly not visible
18// to COM components. If you need to access a type in this assembly from 18// to COM components. If you need to access a type in this assembly from
19// COM, set the ComVisible attribute to true on that type. 19// COM, set the ComVisible attribute to true on that type.
20[assembly: ComVisible(false)] 20[assembly: ComVisible(false)]
21 21
@@ -25,7 +25,7 @@ using System.Runtime.InteropServices;
25// Version information for an assembly consists of the following four values: 25// Version information for an assembly consists of the following four values:
26// 26//
27// Major Version 27// Major Version
28// Minor Version 28// Minor Version
29// Build Number 29// Build Number
30// Revision 30// Revision
31// 31//