From 5e4d6cab00cb29cd088ab7b62ab13aff103b64cb Mon Sep 17 00:00:00 2001 From: onefang Date: Sun, 19 May 2019 21:24:15 +1000 Subject: Dump OpenSim 0.9.0.1 into it's own branch. --- .../AvatarPickerSearchHandler.cs | 2 +- .../Handlers/FetchInventory/FetchInvDescHandler.cs | 46 ++- .../FetchInventory/FetchInventory2Handler.cs | 33 +- .../FetchInventory2ServerConnector.cs | 71 ++++ .../Tests/FetchInventory2HandlerTests.cs | 2 +- .../FetchInventoryDescendents2HandlerTests.cs | 7 +- .../GetDisplayNames/GetDisplayNamesHandler.cs | 61 ++-- .../GetDisplayNamesServerConnector.cs | 2 - .../Handlers/GetMesh/GetMeshHandler.cs | 332 +++++++++-------- .../Handlers/GetMesh/GetMeshServerConnector.cs | 16 +- .../Handlers/GetTexture/GetTextureHandler.cs | 267 +++++++------- .../Handlers/GetTexture/GetTextureRobustHandler.cs | 394 +++++++++++++++++++++ .../GetTexture/GetTextureServerConnector.cs | 6 +- .../GetTexture/Tests/GetTextureHandlerTests.cs | 4 +- .../Handlers/Properties/AssemblyInfo.cs | 10 +- .../UploadBakedTextureHandler.cs | 26 +- .../UploadBakedTextureServerConnector.cs | 2 +- 17 files changed, 875 insertions(+), 406 deletions(-) create mode 100644 OpenSim/Capabilities/Handlers/FetchInventory/FetchInventory2ServerConnector.cs create mode 100644 OpenSim/Capabilities/Handlers/GetTexture/GetTextureRobustHandler.cs (limited to 'OpenSim/Capabilities/Handlers') 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 int page_size = (string.IsNullOrEmpty(psize) ? 500 : Int32.Parse(psize)); int page_number = (string.IsNullOrEmpty(pnumber) ? 1 : Int32.Parse(pnumber)); - + // Full content request httpResponse.StatusCode = (int)System.Net.HttpStatusCode.OK; //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; namespace OpenSim.Capabilities.Handlers { - public class FetchInvDescHandler + public class FetchInvDescHandler { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); @@ -53,14 +53,14 @@ namespace OpenSim.Capabilities.Handlers private IScene m_Scene; // private object m_fetchLock = new Object(); - public FetchInvDescHandler(IInventoryService invService, ILibraryService libService, IScene s) + public FetchInvDescHandler(IInventoryService invService, ILibraryService libService, IScene s) { m_InventoryService = invService; m_LibraryService = libService; m_Scene = s; } - + public string FetchInventoryDescendentsRequest(string request, string path, string param, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) { //m_log.DebugFormat("[XXX]: FetchInventoryDescendentsRequest in {0}, {1}", (m_Scene == null) ? "none" : m_Scene.Name, request); @@ -72,14 +72,14 @@ namespace OpenSim.Capabilities.Handlers // correctly mark it as a uuid // request = request.Replace("00000000-0000-0000-0000-000000000000", "00000000-0000-0000-0000-000000000000"); - + // another hack 1 results in a // System.ArgumentException: Object type System.Int32 cannot // be converted to target type: System.Boolean // request = request.Replace("fetch_folders0", "fetch_folders0"); request = request.Replace("fetch_folders1", "fetch_folders1"); - + Hashtable hash = new Hashtable(); try { @@ -90,9 +90,9 @@ namespace OpenSim.Capabilities.Handlers m_log.ErrorFormat("[WEB FETCH INV DESC HANDLER]: Fetch error: {0}{1}" + e.Message, e.StackTrace); m_log.Error("Request: " + request); } - + ArrayList foldersrequested = (ArrayList)hash["folders"]; - + string response = ""; string bad_folders_response = ""; @@ -403,10 +403,7 @@ namespace OpenSim.Capabilities.Handlers return contents; } contents = fetchedContents; - InventoryFolderBase containingFolder = new InventoryFolderBase(); - containingFolder.ID = folderID; - containingFolder.Owner = agentID; - containingFolder = m_InventoryService.GetFolder(containingFolder); + InventoryFolderBase containingFolder = m_InventoryService.GetFolder(agentID, folderID); if (containingFolder != null) { @@ -416,7 +413,7 @@ namespace OpenSim.Capabilities.Handlers version = containingFolder.Version; - if (fetchItems) + if (fetchItems && containingFolder.Type != (short)FolderType.Trash) { List itemsToReturn = contents.Items; List originalItems = new List(itemsToReturn); @@ -429,7 +426,7 @@ namespace OpenSim.Capabilities.Handlers { if (item.AssetType == (int)AssetType.Link) { - InventoryItemBase linkedItem = m_InventoryService.GetItem(new InventoryItemBase(item.AssetID)); + InventoryItemBase linkedItem = m_InventoryService.GetItem(agentID, item.AssetID); // Take care of genuinely broken links where the target doesn't exist // 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 } // Now scan for folder links and insert the items they target and those links at the head of the return data + +/* dont send contents of LinkFolders. +from docs seems this was never a spec + foreach (InventoryItemBase item in originalItems) { if (item.AssetType == (int)AssetType.LinkFolder) @@ -471,6 +472,7 @@ namespace OpenSim.Capabilities.Handlers } } } +*/ } // foreach (InventoryItemBase item in contents.Items) @@ -514,7 +516,7 @@ namespace OpenSim.Capabilities.Handlers // } // } // } -// +// // foreach (UUID linkedItemFolderId in linkedItemFolderIdsToSend) // { // m_log.DebugFormat( @@ -654,10 +656,7 @@ namespace OpenSim.Capabilities.Handlers // Must fetch it individually else if (contents.FolderID == UUID.Zero) { - InventoryFolderBase containingFolder = new InventoryFolderBase(); - containingFolder.ID = freq.folder_id; - containingFolder.Owner = freq.owner_id; - containingFolder = m_InventoryService.GetFolder(containingFolder); + InventoryFolderBase containingFolder = m_InventoryService.GetFolder(freq.owner_id, freq.folder_id); if (containingFolder != null) { @@ -723,8 +722,8 @@ namespace OpenSim.Capabilities.Handlers if (item.AssetType == (int)AssetType.Link) itemIDs.Add(item.AssetID); - else if (item.AssetType == (int)AssetType.LinkFolder) - folderIDs.Add(item.AssetID); +// else if (item.AssetType == (int)AssetType.LinkFolder) +// folderIDs.Add(item.AssetID); } //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 m_log.WarnFormat("[WEB FETCH INV DESC HANDLER]: GetMultipleItems failed. Falling back to fetching inventory items one by one."); linked = new InventoryItemBase[itemIDs.Count]; int i = 0; - InventoryItemBase item = new InventoryItemBase(); - item.Owner = freq.owner_id; foreach (UUID id in itemIDs) { - item.ID = id; - linked[i++] = m_InventoryService.GetItem(item); + linked[i++] = m_InventoryService.GetItem(freq.owner_id, id); } } @@ -845,4 +841,4 @@ namespace OpenSim.Capabilities.Handlers public InventoryCollection Collection; public int Descendents; } -} \ No newline at end of file +} 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 UUID[] itemIDs = new UUID[itemsRequested.Count]; int i = 0; + foreach (OSDMap osdItemId in itemsRequested) { itemIDs[i++] = osdItemId["item_id"].AsUUID(); } - InventoryItemBase[] items = m_inventoryService.GetMultipleItems(m_agentID, itemIDs); + InventoryItemBase[] items = null; - if (items == null) + if (m_agentID != UUID.Zero) { - // OMG!!! One by one!!! This is fallback code, in case the backend isn't updated - m_log.WarnFormat("[FETCH INVENTORY HANDLER]: GetMultipleItems failed. Falling back to fetching inventory items one by one."); - items = new InventoryItemBase[itemsRequested.Count]; - i = 0; - InventoryItemBase item = new InventoryItemBase(); - item.Owner = m_agentID; - foreach (UUID id in itemIDs) + items = m_inventoryService.GetMultipleItems(m_agentID, itemIDs); + + if (items == null) { - item.ID = id; - items[i++] = m_inventoryService.GetItem(item); + // OMG!!! One by one!!! This is fallback code, in case the backend isn't updated + m_log.WarnFormat("[FETCH INVENTORY HANDLER]: GetMultipleItems failed. Falling back to fetching inventory items one by one."); + items = new InventoryItemBase[itemsRequested.Count]; + foreach (UUID id in itemIDs) + items[i++] = m_inventoryService.GetItem(m_agentID, id); } } + else + { + items = new InventoryItemBase[itemsRequested.Count]; + foreach (UUID id in itemIDs) + items[i++] = m_inventoryService.GetItem(UUID.Zero, id); + } foreach (InventoryItemBase item in items) { @@ -93,7 +99,6 @@ namespace OpenSim.Capabilities.Handlers // We don't know the agent that this request belongs to so we'll use the agent id of the item // which will be the same for all items. llsdReply.agent_id = item.Owner; - llsdReply.items.Array.Add(ConvertInventoryItem(item)); } } @@ -114,7 +119,7 @@ namespace OpenSim.Capabilities.Handlers llsdItem.asset_id = invItem.AssetID; llsdItem.created_at = invItem.CreationDate; llsdItem.desc = invItem.Description; - llsdItem.flags = (int)invItem.Flags; + llsdItem.flags = ((int)invItem.Flags) & 0xff; llsdItem.item_id = invItem.ID; llsdItem.name = invItem.Name; llsdItem.parent_id = invItem.Folder; @@ -138,4 +143,4 @@ namespace OpenSim.Capabilities.Handlers return llsdItem; } } -} \ No newline at end of file +} 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 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using Nini.Config; +using OpenSim.Server.Base; +using OpenSim.Services.Interfaces; +using OpenSim.Framework.Servers.HttpServer; +using OpenSim.Server.Handlers.Base; +using OpenMetaverse; + +namespace OpenSim.Capabilities.Handlers +{ + public class FetchInventory2ServerConnector : ServiceConnector + { + private IInventoryService m_InventoryService; + private string m_ConfigName = "CapsService"; + + public FetchInventory2ServerConnector(IConfigSource config, IHttpServer server, string configName) + : base(config, server, configName) + { + if (configName != String.Empty) + m_ConfigName = configName; + + IConfig serverConfig = config.Configs[m_ConfigName]; + if (serverConfig == null) + throw new Exception(String.Format("No section '{0}' in config file", m_ConfigName)); + + string invService = serverConfig.GetString("InventoryService", String.Empty); + + if (invService == String.Empty) + throw new Exception("No InventoryService in config file"); + + Object[] args = new Object[] { config }; + m_InventoryService = ServerUtils.LoadPlugin(invService, args); + + if (m_InventoryService == null) + throw new Exception(String.Format("Failed to load InventoryService from {0}; config is {1}", invService, m_ConfigName)); + + FetchInventory2Handler fiHandler = new FetchInventory2Handler(m_InventoryService, UUID.Zero); + IRequestHandler reqHandler + = new RestStreamHandler( + "POST", "/CAPS/FetchInventory/", fiHandler.FetchInventoryRequest, "FetchInventory", null); + server.AddStreamHandler(reqHandler); + } + } +} 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 string request = "itemsitem_id"; request += "10000000-0000-0000-0000-000000000001"; // Notecard 1 request += ""; - + string llsdresponse = handler.FetchInventoryRequest(request, "/FETCH", string.Empty, req, resp); 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 string request = "foldersfetch_folders1fetch_items1folder_id"; request += m_rootFolderID; request += "owner_id00000000-0000-0000-0000-000000000000sort_order1"; - + string llsdresponse = handler.FetchInventoryDescendentsRequest(request, "/FETCH", string.Empty, req, resp); Assert.That(llsdresponse != null, Is.True, "Incorrect null response"); @@ -203,7 +203,7 @@ namespace OpenSim.Capabilities.Handlers.FetchInventory.Tests // Make sure that the note card link is included Assert.That(llsdresponse.Contains("Link to notecard"), Is.True, "Link to notecard is missing"); - + //Make sure the notecard item itself is included Assert.That(llsdresponse.Contains("Test Notecard 2"), Is.True, "Notecard 2 item (the source) is missing"); @@ -215,10 +215,11 @@ namespace OpenSim.Capabilities.Handlers.FetchInventory.Tests // Make sure the folder link is included Assert.That(llsdresponse.Contains("Link to Objects folder"), Is.True, "Link to Objects folder is missing"); +/* contents of link folder are not supposed to be listed // Make sure the objects inside the Objects folder are included // Note: I'm not entirely sure this is needed, but that's what I found in the implementation Assert.That(llsdresponse.Contains("Some Object"), Is.True, "Some Object item (contents of the source) is missing"); - +*/ // Make sure that the source item is before the link item pos1 = llsdresponse.IndexOf("Some Object"); 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; using System.Collections; using System.Collections.Generic; using System.Collections.Specialized; -using System.Drawing; -using System.Drawing.Imaging; using System.Reflection; using System.IO; using System.Web; @@ -38,12 +36,7 @@ using log4net; using Nini.Config; using OpenMetaverse; using OpenMetaverse.StructuredData; -using OpenMetaverse.Imaging; -using OpenSim.Framework; -using OpenSim.Framework.Capabilities; -using OpenSim.Framework.Servers; using OpenSim.Framework.Servers.HttpServer; -using OpenSim.Region.Framework.Interfaces; using OpenSim.Services.Interfaces; using Caps = OpenSim.Framework.Capabilities.Caps; using OSDMap = OpenMetaverse.StructuredData.OSDMap; @@ -55,7 +48,7 @@ namespace OpenSim.Capabilities.Handlers { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - private IUserManagement m_UserManagement; + protected IUserManagement m_UserManagement; public GetDisplayNamesHandler(string path, IUserManagement umService, string name, string description) : base("GET", path, name, description) @@ -65,12 +58,11 @@ namespace OpenSim.Capabilities.Handlers protected override byte[] ProcessRequest(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) { - m_log.DebugFormat("[GET_DISPLAY_NAMES]: called {0}", httpRequest.Url.Query); +// m_log.DebugFormat("[GET_DISPLAY_NAMES]: called {0}", httpRequest.Url.Query); NameValueCollection query = HttpUtility.ParseQueryString(httpRequest.Url.Query); string[] ids = query.GetValues("ids"); - if (m_UserManagement == null) { m_log.Error("[GET_DISPLAY_NAMES]: Cannot fetch display names without a user management component"); @@ -78,32 +70,39 @@ namespace OpenSim.Capabilities.Handlers return new byte[0]; } + Dictionary names = m_UserManagement.GetUsersNames(ids); + OSDMap osdReply = new OSDMap(); OSDArray agents = new OSDArray(); osdReply["agents"] = agents; - foreach (string id in ids) + foreach (KeyValuePair kvp in names) { - UUID uuid = UUID.Zero; - if (UUID.TryParse(id, out uuid)) - { - string name = m_UserManagement.GetUserName(uuid); - if (!string.IsNullOrEmpty(name)) - { - string[] parts = name.Split(new char[] {' '}); - OSDMap osdname = new OSDMap(); - osdname["display_name_next_update"] = OSD.FromDate(DateTime.MinValue); - osdname["display_name_expires"] = OSD.FromDate(DateTime.Now.AddMonths(1)); - osdname["display_name"] = OSD.FromString(name); - osdname["legacy_first_name"] = parts[0]; - osdname["legacy_last_name"] = parts[1]; - osdname["username"] = OSD.FromString(name); - osdname["id"] = OSD.FromUUID(uuid); - osdname["is_display_name_default"] = OSD.FromBoolean(true); + if (string.IsNullOrEmpty(kvp.Value)) + continue; + if(kvp.Key == UUID.Zero) + continue; - agents.Add(osdname); - } + string[] parts = kvp.Value.Split(new char[] {' '}); + OSDMap osdname = new OSDMap(); + if(parts[0] == "Unknown") + { + osdname["display_name_next_update"] = OSD.FromDate(DateTime.UtcNow.AddHours(1)); + osdname["display_name_expires"] = OSD.FromDate(DateTime.UtcNow.AddHours(2)); } + else + { + osdname["display_name_next_update"] = OSD.FromDate(DateTime.UtcNow.AddDays(8)); + osdname["display_name_expires"] = OSD.FromDate(DateTime.UtcNow.AddMonths(1)); + } + osdname["display_name"] = OSD.FromString(kvp.Value); + osdname["legacy_first_name"] = parts[0]; + osdname["legacy_last_name"] = parts[1]; + osdname["username"] = OSD.FromString(kvp.Value); + osdname["id"] = OSD.FromUUID(kvp.Key); + osdname["is_display_name_default"] = OSD.FromBoolean(true); + + agents.Add(osdname); } // Full content request @@ -113,8 +112,6 @@ namespace OpenSim.Capabilities.Handlers string reply = OSDParser.SerializeLLSDXmlString(osdReply); return System.Text.Encoding.UTF8.GetBytes(reply); - } - } -} \ No newline at end of file +} 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 if (m_UserManagement == null) throw new Exception(String.Format("Failed to load UserManagement from {0}; config is {1}", umService, m_ConfigName)); - string rurl = serverConfig.GetString("GetTextureRedirectURL"); - server.AddStreamHandler( new GetDisplayNamesHandler("/CAPS/agents/", m_UserManagement, "GetDisplayNames", null)); } 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 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +using System; +using System.Collections; +using System.Collections.Specialized; +using System.Reflection; +using System.IO; +using System.Web; using log4net; +using Nini.Config; using OpenMetaverse; -using OpenMetaverse.Imaging; +using OpenMetaverse.StructuredData; using OpenSim.Framework; +using OpenSim.Framework.Servers; using OpenSim.Framework.Servers.HttpServer; using OpenSim.Services.Interfaces; -using System; -using System.Collections.Specialized; -using System.Drawing; -using System.Drawing.Imaging; -using System.IO; -using System.Reflection; -using System.Web; +using Caps = OpenSim.Framework.Capabilities.Caps; + + + namespace OpenSim.Capabilities.Handlers { - public class GetMeshHandler : BaseStreamHandler + public class GetMeshHandler { private static readonly ILog m_log = - LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + private IAssetService m_assetService; - // TODO: Change this to a config option - private string m_RedirectURL = null; + public const string DefaultFormat = "vnd.ll.mesh"; - public GetMeshHandler(string path, IAssetService assService, string name, string description, string redirectURL) - : base("GET", path, name, description) + public GetMeshHandler(IAssetService assService) { m_assetService = assService; - m_RedirectURL = redirectURL; - if (m_RedirectURL != null && !m_RedirectURL.EndsWith("/")) - m_RedirectURL += "/"; } - - protected override byte[] ProcessRequest(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) + public Hashtable Handle(Hashtable request) { - // Try to parse the texture ID from the request URL - NameValueCollection query = HttpUtility.ParseQueryString(httpRequest.Url.Query); - string textureStr = query.GetOne("mesh_id"); + Hashtable ret = new Hashtable(); + ret["int_response_code"] = (int)System.Net.HttpStatusCode.NotFound; + ret["content_type"] = "text/plain"; + ret["keepalive"] = false; + ret["reusecontext"] = false; + ret["int_bytes"] = 0; + ret["int_lod"] = 0; + string MeshStr = (string)request["mesh_id"]; + + + //m_log.DebugFormat("[GETMESH]: called {0}", MeshStr); if (m_assetService == null) { - m_log.Error("[GETMESH]: Cannot fetch mesh " + textureStr + " without an asset service"); - httpResponse.StatusCode = (int)System.Net.HttpStatusCode.NotFound; + m_log.Error("[GETMESH]: Cannot fetch mesh " + MeshStr + " without an asset service"); } UUID meshID; - if (!String.IsNullOrEmpty(textureStr) && UUID.TryParse(textureStr, out meshID)) + if (!String.IsNullOrEmpty(MeshStr) && UUID.TryParse(MeshStr, out meshID)) { - // OK, we have an array with preferred formats, possibly with only one entry - - httpResponse.StatusCode = (int)System.Net.HttpStatusCode.NotFound; - AssetBase mesh; - - if (!String.IsNullOrEmpty(m_RedirectURL)) - { - // Only try to fetch locally cached meshes. Misses are redirected - mesh = m_assetService.GetCached(meshID.ToString()); + // m_log.DebugFormat("[GETMESH]: Received request for mesh id {0}", meshID); - if (mesh != null) - { - if (mesh.Type != (sbyte)AssetType.Mesh) - { - httpResponse.StatusCode = (int)System.Net.HttpStatusCode.NotFound; - } - WriteMeshData(httpRequest, httpResponse, mesh); - } - else - { - string textureUrl = m_RedirectURL + "?mesh_id="+ meshID.ToString(); - m_log.Debug("[GETMESH]: Redirecting mesh request to " + textureUrl); - httpResponse.StatusCode = (int)OSHttpStatusCode.RedirectMovedPermanently; - httpResponse.RedirectLocation = textureUrl; - return null; - } - } - else // no redirect - { - // try the cache - mesh = m_assetService.GetCached(meshID.ToString()); - if (mesh == null) - { - // Fetch locally or remotely. Misses return a 404 - mesh = m_assetService.Get(meshID.ToString()); + ret = ProcessGetMesh(request, UUID.Zero, null); - if (mesh != null) - { - if (mesh.Type != (sbyte)AssetType.Mesh) - { - httpResponse.StatusCode = (int)System.Net.HttpStatusCode.NotFound; - return null; - } - WriteMeshData(httpRequest, httpResponse, mesh); - return null; - } - } - else // it was on the cache - { - if (mesh.Type != (sbyte)AssetType.Mesh) - { - httpResponse.StatusCode = (int)System.Net.HttpStatusCode.NotFound; - return null; - } - WriteMeshData(httpRequest, httpResponse, mesh); - return null; - } - } - // not found - httpResponse.StatusCode = (int)System.Net.HttpStatusCode.NotFound; - return null; } else { - m_log.Warn("[GETTEXTURE]: Failed to parse a mesh_id from GetMesh request: " + httpRequest.Url); + m_log.Warn("[GETMESH]: Failed to parse a mesh_id from GetMesh request: " + (string)request["uri"]); } - return null; - } - private void WriteMeshData(IOSHttpRequest request, IOSHttpResponse response, AssetBase texture) + return ret; + } + public Hashtable ProcessGetMesh(Hashtable request, UUID AgentId, Caps cap) { - string range = request.Headers.GetOne("Range"); + Hashtable responsedata = new Hashtable(); + responsedata["int_response_code"] = 400; //501; //410; //404; + responsedata["content_type"] = "text/plain"; + responsedata["keepalive"] = false; + responsedata["str_response_string"] = "Request wasn't what was expected"; + responsedata["reusecontext"] = false; + responsedata["int_lod"] = 0; + responsedata["int_bytes"] = 0; + + string meshStr = string.Empty; - if (!String.IsNullOrEmpty(range)) + if (request.ContainsKey("mesh_id")) + meshStr = request["mesh_id"].ToString(); + + UUID meshID = UUID.Zero; + if (!String.IsNullOrEmpty(meshStr) && UUID.TryParse(meshStr, out meshID)) { - // Range request - int start, end; - if (TryParseRange(range, out start, out end)) + if (m_assetService == null) { - // Before clamping start make sure we can satisfy it in order to avoid - // sending back the last byte instead of an error status - if (start >= texture.Data.Length) - { - response.StatusCode = (int)System.Net.HttpStatusCode.PartialContent; - response.ContentType = texture.Metadata.ContentType; - } - else + responsedata["int_response_code"] = 404; //501; //410; //404; + responsedata["content_type"] = "text/plain"; + responsedata["keepalive"] = false; + responsedata["str_response_string"] = "The asset service is unavailable. So is your mesh."; + responsedata["reusecontext"] = false; + return responsedata; + } + + AssetBase mesh = m_assetService.Get(meshID.ToString()); + + if (mesh != null) + { + if (mesh.Type == (SByte)AssetType.Mesh) { - // Handle the case where no second range value was given. This is equivalent to requesting - // the rest of the entity. - if (end == -1) - end = int.MaxValue; - end = Utils.Clamp(end, 0, texture.Data.Length - 1); - start = Utils.Clamp(start, 0, end); - int len = end - start + 1; + Hashtable headers = new Hashtable(); + responsedata["headers"] = headers; + + string range = String.Empty; + + if (((Hashtable)request["headers"])["range"] != null) + range = (string)((Hashtable)request["headers"])["range"]; - if (0 == start && len == texture.Data.Length) + else if (((Hashtable)request["headers"])["Range"] != null) + range = (string)((Hashtable)request["headers"])["Range"]; + + if (!String.IsNullOrEmpty(range)) // Mesh Asset LOD // Physics { - response.StatusCode = (int)System.Net.HttpStatusCode.OK; + // Range request + int start, end; + if (TryParseRange(range, out start, out end)) + { + // Before clamping start make sure we can satisfy it in order to avoid + // sending back the last byte instead of an error status + if (start >= mesh.Data.Length) + { + responsedata["int_response_code"] = 404; //501; //410; //404; + responsedata["content_type"] = "text/plain"; + responsedata["keepalive"] = false; + responsedata["str_response_string"] = "This range doesnt exist."; + responsedata["reusecontext"] = false; + responsedata["int_lod"] = 3; + return responsedata; + } + else + { + end = Utils.Clamp(end, 0, mesh.Data.Length - 1); + start = Utils.Clamp(start, 0, end); + int len = end - start + 1; + + //m_log.Debug("Serving " + start + " to " + end + " of " + texture.Data.Length + " bytes for texture " + texture.ID); + + if (start > 20000) + { + responsedata["int_lod"] = 3; + } + else if (start < 4097) + { + responsedata["int_lod"] = 1; + } + else + { + responsedata["int_lod"] = 2; + } + + + if (start == 0 && len == mesh.Data.Length) // well redudante maybe + { + responsedata["int_response_code"] = (int)System.Net.HttpStatusCode.OK; + responsedata["bin_response_data"] = mesh.Data; + responsedata["int_bytes"] = mesh.Data.Length; + responsedata["reusecontext"] = false; + responsedata["int_lod"] = 3; + + } + else + { + responsedata["int_response_code"] = + (int)System.Net.HttpStatusCode.PartialContent; + headers["Content-Range"] = String.Format("bytes {0}-{1}/{2}", start, end, + mesh.Data.Length); + + byte[] d = new byte[len]; + Array.Copy(mesh.Data, start, d, 0, len); + responsedata["bin_response_data"] = d; + responsedata["int_bytes"] = len; + responsedata["reusecontext"] = false; + } + } + } + else + { + m_log.Warn("[GETMESH]: Failed to parse a range from GetMesh request, sending full asset: " + (string)request["uri"]); + responsedata["str_response_string"] = Convert.ToBase64String(mesh.Data); + responsedata["content_type"] = "application/vnd.ll.mesh"; + responsedata["int_response_code"] = 200; + responsedata["reusecontext"] = false; + responsedata["int_lod"] = 3; + } } else { - response.StatusCode = (int)System.Net.HttpStatusCode.PartialContent; - response.AddHeader("Content-Range", String.Format("bytes {0}-{1}/{2}", start, end, texture.Data.Length)); + responsedata["str_response_string"] = Convert.ToBase64String(mesh.Data); + responsedata["content_type"] = "application/vnd.ll.mesh"; + responsedata["int_response_code"] = 200; + responsedata["reusecontext"] = false; + responsedata["int_lod"] = 3; } - - response.ContentLength = len; - response.ContentType = "application/vnd.ll.mesh"; - - response.Body.Write(texture.Data, start, len); + } + // Optionally add additional mesh types here + else + { + responsedata["int_response_code"] = 404; //501; //410; //404; + responsedata["content_type"] = "text/plain"; + responsedata["keepalive"] = false; + responsedata["str_response_string"] = "Unfortunately, this asset isn't a mesh."; + responsedata["reusecontext"] = false; + responsedata["int_lod"] = 1; + return responsedata; } } else { - m_log.Warn("[GETMESH]: Malformed Range header: " + range); - response.StatusCode = (int)System.Net.HttpStatusCode.BadRequest; + responsedata["int_response_code"] = 404; //501; //410; //404; + responsedata["content_type"] = "text/plain"; + responsedata["keepalive"] = false; + responsedata["str_response_string"] = "Your Mesh wasn't found. Sorry!"; + responsedata["reusecontext"] = false; + responsedata["int_lod"] = 0; + return responsedata; } } - else - { - // Full content request - response.StatusCode = (int)System.Net.HttpStatusCode.OK; - response.ContentLength = texture.Data.Length; - response.ContentType = "application/vnd.ll.mesh"; - response.Body.Write(texture.Data, 0, texture.Data.Length); - } - } - /// - /// Parse a range header. - /// - /// - /// As per http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html, - /// this obeys range headers with two values (e.g. 533-4165) and no second value (e.g. 533-). - /// Where there is no value, -1 is returned. - /// FIXME: Need to cover the case where only a second value is specified (e.g. -4165), probably by returning -1 - /// for start. - /// - /// - /// Start of the range. Undefined if this was not a number. - /// End of the range. Will be -1 if no end specified. Undefined if there was a raw string but this was not a number. + return responsedata; + } private bool TryParseRange(string header, out int start, out int end) { - start = end = 0; - if (header.StartsWith("bytes=")) { string[] rangeValues = header.Substring(6).Split('-'); - if (rangeValues.Length == 2) { - if (!Int32.TryParse(rangeValues[0], out start)) - return false; - - string rawEnd = rangeValues[1]; - - if (rawEnd == "") - { - end = -1; + if (Int32.TryParse(rangeValues[0], out start) && Int32.TryParse(rangeValues[1], out end)) return true; - } - else if (Int32.TryParse(rawEnd, out end)) - { - return true; - } } } 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 string rurl = serverConfig.GetString("GetMeshRedirectURL"); - server.AddStreamHandler( - new GetTextureHandler("/CAPS/GetMesh/" /*+ UUID.Random() */, m_AssetService, "GetMesh", null, rurl)); - - rurl = serverConfig.GetString("GetMesh2RedirectURL"); - - server.AddStreamHandler( - new GetTextureHandler("/CAPS/GetMesh2/" /*+ UUID.Random() */, m_AssetService, "GetMesh2", null, rurl)); + GetMeshHandler gmeshHandler = new GetMeshHandler(m_AssetService); + IRequestHandler reqHandler + = new RestHTTPHandler( + "GET", + "/CAPS/" + UUID.Random(), + httpMethod => gmeshHandler.ProcessGetMesh(httpMethod, UUID.Zero, null), + "GetMesh", + null); + server.AddStreamHandler(reqHandler); ; } } } \ 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; namespace OpenSim.Capabilities.Handlers { - public class GetTextureHandler : BaseStreamHandler + public class GetTextureHandler { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + private IAssetService m_assetService; public const string DefaultFormat = "x-j2c"; - // TODO: Change this to a config option - private string m_RedirectURL = null; - - public GetTextureHandler(string path, IAssetService assService, string name, string description, string redirectURL) - : base("GET", path, name, description) + public GetTextureHandler(IAssetService assService) { m_assetService = assService; - m_RedirectURL = redirectURL; - if (m_RedirectURL != null && !m_RedirectURL.EndsWith("/")) - m_RedirectURL += "/"; } - protected override byte[] ProcessRequest(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) + public Hashtable Handle(Hashtable request) { - // Try to parse the texture ID from the request URL - NameValueCollection query = HttpUtility.ParseQueryString(httpRequest.Url.Query); - string textureStr = query.GetOne("texture_id"); - string format = query.GetOne("format"); + Hashtable ret = new Hashtable(); + ret["int_response_code"] = (int)System.Net.HttpStatusCode.NotFound; + ret["content_type"] = "text/plain"; + ret["keepalive"] = false; + ret["reusecontext"] = false; + ret["int_bytes"] = 0; + string textureStr = (string)request["texture_id"]; + string format = (string)request["format"]; //m_log.DebugFormat("[GETTEXTURE]: called {0}", textureStr); if (m_assetService == null) { m_log.Error("[GETTEXTURE]: Cannot fetch texture " + textureStr + " without an asset service"); - httpResponse.StatusCode = (int)System.Net.HttpStatusCode.NotFound; } UUID textureID; if (!String.IsNullOrEmpty(textureStr) && UUID.TryParse(textureStr, out textureID)) { // m_log.DebugFormat("[GETTEXTURE]: Received request for texture id {0}", textureID); - + string[] formats; if (!string.IsNullOrEmpty(format)) { @@ -94,41 +91,52 @@ namespace OpenSim.Capabilities.Handlers } else { - formats = WebUtil.GetPreferredImageTypes(httpRequest.Headers.Get("Accept")); + formats = new string[1] { DefaultFormat }; // default + if (((Hashtable)request["headers"])["Accept"] != null) + formats = WebUtil.GetPreferredImageTypes((string)((Hashtable)request["headers"])["Accept"]); if (formats.Length == 0) formats = new string[1] { DefaultFormat }; // default } // OK, we have an array with preferred formats, possibly with only one entry - - httpResponse.StatusCode = (int)System.Net.HttpStatusCode.NotFound; + bool foundtexture = false; foreach (string f in formats) { - if (FetchTexture(httpRequest, httpResponse, textureID, f)) + foundtexture = FetchTexture(request, ret, textureID, f); + if (foundtexture) break; } + if (!foundtexture) + { + ret["int_response_code"] = 404; + ret["error_status_text"] = "not found"; + ret["str_response_string"] = "not found"; + ret["content_type"] = "text/plain"; + ret["keepalive"] = false; + ret["reusecontext"] = false; + ret["int_bytes"] = 0; + } } else { - m_log.Warn("[GETTEXTURE]: Failed to parse a texture_id from GetTexture request: " + httpRequest.Url); + m_log.Warn("[GETTEXTURE]: Failed to parse a texture_id from GetTexture request: " + (string)request["uri"]); } // m_log.DebugFormat( // "[GETTEXTURE]: For texture {0} sending back response {1}, data length {2}", // textureID, httpResponse.StatusCode, httpResponse.ContentLength); - - return null; + return ret; } /// - /// + /// /// /// /// /// /// /// False for "caller try another codec"; true otherwise - private bool FetchTexture(IOSHttpRequest httpRequest, IOSHttpResponse httpResponse, UUID textureID, string format) + private bool FetchTexture(Hashtable request, Hashtable response, UUID textureID, string format) { // m_log.DebugFormat("[GETTEXTURE]: {0} with requested format {1}", textureID, format); AssetBase texture; @@ -137,86 +145,70 @@ namespace OpenSim.Capabilities.Handlers if (format != DefaultFormat) fullID = fullID + "-" + format; - if (!String.IsNullOrEmpty(m_RedirectURL)) + // try the cache + texture = m_assetService.GetCached(fullID); + + if (texture == null) { - // Only try to fetch locally cached textures. Misses are redirected - texture = m_assetService.GetCached(fullID); + //m_log.DebugFormat("[GETTEXTURE]: texture was not in the cache"); + + // Fetch locally or remotely. Misses return a 404 + texture = m_assetService.Get(textureID.ToString()); if (texture != null) { if (texture.Type != (sbyte)AssetType.Texture) + return true; + + if (format == DefaultFormat) { - httpResponse.StatusCode = (int)System.Net.HttpStatusCode.NotFound; + WriteTextureData(request, response, texture, format); + return true; + } + else + { + AssetBase newTexture = new AssetBase(texture.ID + "-" + format, texture.Name, (sbyte)AssetType.Texture, texture.Metadata.CreatorID); + newTexture.Data = ConvertTextureData(texture, format); + if (newTexture.Data.Length == 0) + return false; // !!! Caller try another codec, please! + + newTexture.Flags = AssetFlags.Collectable; + newTexture.Temporary = true; + newTexture.Local = true; + m_assetService.Store(newTexture); + WriteTextureData(request, response, newTexture, format); return true; } - WriteTextureData(httpRequest, httpResponse, texture, format); - } - else - { - string textureUrl = m_RedirectURL + "?texture_id="+ textureID.ToString(); - m_log.Debug("[GETTEXTURE]: Redirecting texture request to " + textureUrl); - httpResponse.StatusCode = (int)OSHttpStatusCode.RedirectMovedPermanently; - httpResponse.RedirectLocation = textureUrl; - return true; } - } - else // no redirect - { - // try the cache - texture = m_assetService.GetCached(fullID); + } + else // it was on the cache + { + //m_log.DebugFormat("[GETTEXTURE]: texture was in the cache"); + WriteTextureData(request, response, texture, format); + return true; + } - if (texture == null) - { -// m_log.DebugFormat("[GETTEXTURE]: texture was not in the cache"); - - // Fetch locally or remotely. Misses return a 404 - texture = m_assetService.Get(textureID.ToString()); + //response = new Hashtable(); - if (texture != null) - { - if (texture.Type != (sbyte)AssetType.Texture) - { - httpResponse.StatusCode = (int)System.Net.HttpStatusCode.NotFound; - return true; - } - if (format == DefaultFormat) - { - WriteTextureData(httpRequest, httpResponse, texture, format); - return true; - } - else - { - AssetBase newTexture = new AssetBase(texture.ID + "-" + format, texture.Name, (sbyte)AssetType.Texture, texture.Metadata.CreatorID); - newTexture.Data = ConvertTextureData(texture, format); - if (newTexture.Data.Length == 0) - return false; // !!! Caller try another codec, please! - - newTexture.Flags = AssetFlags.Collectable; - newTexture.Temporary = true; - newTexture.Local = true; - m_assetService.Store(newTexture); - WriteTextureData(httpRequest, httpResponse, newTexture, format); - return true; - } - } - } - else // it was on the cache - { -// m_log.DebugFormat("[GETTEXTURE]: texture was in the cache"); - WriteTextureData(httpRequest, httpResponse, texture, format); - return true; - } - } + //WriteTextureData(request,response,null,format); // not found -// m_log.Warn("[GETTEXTURE]: Texture " + textureID + " not found"); - httpResponse.StatusCode = (int)System.Net.HttpStatusCode.NotFound; - return true; + //m_log.Warn("[GETTEXTURE]: Texture " + textureID + " not found"); + return false; } - private void WriteTextureData(IOSHttpRequest request, IOSHttpResponse response, AssetBase texture, string format) + private void WriteTextureData(Hashtable request, Hashtable response, AssetBase texture, string format) { - string range = request.Headers.GetOne("Range"); + Hashtable headers = new Hashtable(); + response["headers"] = headers; + + string range = String.Empty; + + if (((Hashtable)request["headers"])["range"] != null) + range = (string)((Hashtable)request["headers"])["range"]; + + else if (((Hashtable)request["headers"])["Range"] != null) + range = (string)((Hashtable)request["headers"])["Range"]; if (!String.IsNullOrEmpty(range)) // JP2's only { @@ -244,10 +236,8 @@ namespace OpenSim.Capabilities.Handlers // However, if we return PartialContent (or OK) instead, the viewer will display that resolution. // response.StatusCode = (int)System.Net.HttpStatusCode.RequestedRangeNotSatisfiable; -// response.AddHeader("Content-Range", String.Format("bytes */{0}", texture.Data.Length)); -// response.StatusCode = (int)System.Net.HttpStatusCode.OK; - response.StatusCode = (int)System.Net.HttpStatusCode.PartialContent; - response.ContentType = texture.Metadata.ContentType; + // viewers don't seem to handle RequestedRangeNotSatisfiable and keep retrying with same parameters + response["int_response_code"] = (int)System.Net.HttpStatusCode.NotFound; } else { @@ -262,41 +252,46 @@ namespace OpenSim.Capabilities.Handlers // m_log.Debug("Serving " + start + " to " + end + " of " + texture.Data.Length + " bytes for texture " + texture.ID); - // Always return PartialContent, even if the range covered the entire data length - // We were accidentally sending back 404 before in this situation - // https://issues.apache.org/bugzilla/show_bug.cgi?id=51878 supports sending 206 even if the - // entire range is requested, and viewer 3.2.2 (and very probably earlier) seems fine with this. - // - // We also do not want to send back OK even if the whole range was satisfiable since this causes - // HTTP textures on at least Imprudence 1.4.0-beta2 to never display the final texture quality. -// if (end > maxEnd) -// response.StatusCode = (int)System.Net.HttpStatusCode.OK; -// else - response.StatusCode = (int)System.Net.HttpStatusCode.PartialContent; - - response.ContentLength = len; - response.ContentType = texture.Metadata.ContentType; - response.AddHeader("Content-Range", String.Format("bytes {0}-{1}/{2}", start, end, texture.Data.Length)); - - response.Body.Write(texture.Data, start, len); + response["content-type"] = texture.Metadata.ContentType; + + if (start == 0 && len == texture.Data.Length) // well redudante maybe + { + response["int_response_code"] = (int)System.Net.HttpStatusCode.OK; + response["bin_response_data"] = texture.Data; + response["int_bytes"] = texture.Data.Length; + } + else + { + response["int_response_code"] = (int)System.Net.HttpStatusCode.PartialContent; + headers["Content-Range"] = String.Format("bytes {0}-{1}/{2}", start, end, texture.Data.Length); + + byte[] d = new byte[len]; + Array.Copy(texture.Data, start, d, 0, len); + response["bin_response_data"] = d; + response["int_bytes"] = len; + } +// response.Body.Write(texture.Data, start, len); } } else { m_log.Warn("[GETTEXTURE]: Malformed Range header: " + range); - response.StatusCode = (int)System.Net.HttpStatusCode.BadRequest; + response["int_response_code"] = (int)System.Net.HttpStatusCode.BadRequest; } } else // JP2's or other formats { // Full content request - response.StatusCode = (int)System.Net.HttpStatusCode.OK; - response.ContentLength = texture.Data.Length; + response["int_response_code"] = (int)System.Net.HttpStatusCode.OK; if (format == DefaultFormat) - response.ContentType = texture.Metadata.ContentType; + response["content_type"] = texture.Metadata.ContentType; else - response.ContentType = "image/" + format; - response.Body.Write(texture.Data, 0, texture.Data.Length); + response["content_type"] = "image/" + format; + + response["bin_response_data"] = texture.Data; + response["int_bytes"] = texture.Data.Length; + +// response.Body.Write(texture.Data, 0, texture.Data.Length); } // if (response.StatusCode < 200 || response.StatusCode > 299) @@ -359,36 +354,35 @@ namespace OpenSim.Capabilities.Handlers byte[] data = new byte[0]; MemoryStream imgstream = new MemoryStream(); - Bitmap mTexture = new Bitmap(1, 1); - ManagedImage managedImage; - Image image = (Image)mTexture; + Bitmap mTexture = null; + ManagedImage managedImage = null; + Image image = null; try { // Taking our jpeg2000 data, decoding it, then saving it to a byte array with regular data - imgstream = new MemoryStream(); - // Decode image to System.Drawing.Image - if (OpenJPEG.DecodeToImage(texture.Data, out managedImage, out image)) + if (OpenJPEG.DecodeToImage(texture.Data, out managedImage, out image) && image != null) { // Save to bitmap mTexture = new Bitmap(image); - EncoderParameters myEncoderParameters = new EncoderParameters(); - myEncoderParameters.Param[0] = new EncoderParameter(Encoder.Quality, 95L); - - // Save bitmap to stream - ImageCodecInfo codec = GetEncoderInfo("image/" + format); - if (codec != null) + using(EncoderParameters myEncoderParameters = new EncoderParameters()) { - mTexture.Save(imgstream, codec, myEncoderParameters); + myEncoderParameters.Param[0] = new EncoderParameter(Encoder.Quality,95L); + + // Save bitmap to stream + ImageCodecInfo codec = GetEncoderInfo("image/" + format); + if (codec != null) + { + mTexture.Save(imgstream, codec, myEncoderParameters); // Write the stream to a byte array for output - data = imgstream.ToArray(); + data = imgstream.ToArray(); + } + else + m_log.WarnFormat("[GETTEXTURE]: No such codec {0}", format); } - else - m_log.WarnFormat("[GETTEXTURE]: No such codec {0}", format); - } } catch (Exception e) @@ -405,11 +399,10 @@ namespace OpenSim.Capabilities.Handlers if (image != null) image.Dispose(); + if(managedImage != null) + managedImage.Clear(); if (imgstream != null) - { - imgstream.Close(); imgstream.Dispose(); - } } return data; @@ -428,4 +421,4 @@ namespace OpenSim.Capabilities.Handlers return null; } } -} \ No newline at end of file +} 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 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections; +using System.Collections.Specialized; +using System.Drawing; +using System.Drawing.Imaging; +using System.Reflection; +using System.IO; +using System.Web; +using log4net; +using Nini.Config; +using OpenMetaverse; +using OpenMetaverse.StructuredData; +using OpenMetaverse.Imaging; +using OpenSim.Framework; +using OpenSim.Framework.Servers; +using OpenSim.Framework.Servers.HttpServer; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Services.Interfaces; +using Caps = OpenSim.Framework.Capabilities.Caps; + +namespace OpenSim.Capabilities.Handlers +{ + public class GetTextureRobustHandler : BaseStreamHandler + { + private static readonly ILog m_log = + LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + private IAssetService m_assetService; + + public const string DefaultFormat = "x-j2c"; + + // TODO: Change this to a config option + private string m_RedirectURL = null; + + public GetTextureRobustHandler(string path, IAssetService assService, string name, string description, string redirectURL) + : base("GET", path, name, description) + { + m_assetService = assService; + m_RedirectURL = redirectURL; + if (m_RedirectURL != null && !m_RedirectURL.EndsWith("/")) + m_RedirectURL += "/"; + } + + protected override byte[] ProcessRequest(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) + { + // Try to parse the texture ID from the request URL + NameValueCollection query = HttpUtility.ParseQueryString(httpRequest.Url.Query); + string textureStr = query.GetOne("texture_id"); + string format = query.GetOne("format"); + + //m_log.DebugFormat("[GETTEXTURE]: called {0}", textureStr); + + if (m_assetService == null) + { + m_log.Error("[GETTEXTURE]: Cannot fetch texture " + textureStr + " without an asset service"); + httpResponse.StatusCode = (int)System.Net.HttpStatusCode.NotFound; + return null; + } + + UUID textureID; + if (!String.IsNullOrEmpty(textureStr) && UUID.TryParse(textureStr, out textureID)) + { +// m_log.DebugFormat("[GETTEXTURE]: Received request for texture id {0}", textureID); + + string[] formats; + if (!string.IsNullOrEmpty(format)) + { + formats = new string[1] { format.ToLower() }; + } + else + { + formats = WebUtil.GetPreferredImageTypes(httpRequest.Headers.Get("Accept")); + if (formats.Length == 0) + formats = new string[1] { DefaultFormat }; // default + + } + // OK, we have an array with preferred formats, possibly with only one entry + + httpResponse.StatusCode = (int)System.Net.HttpStatusCode.NotFound; + foreach (string f in formats) + { + if (FetchTexture(httpRequest, httpResponse, textureID, f)) + break; + } + } + else + { + m_log.Warn("[GETTEXTURE]: Failed to parse a texture_id from GetTexture request: " + httpRequest.Url); + } + +// m_log.DebugFormat( +// "[GETTEXTURE]: For texture {0} sending back response {1}, data length {2}", +// textureID, httpResponse.StatusCode, httpResponse.ContentLength); + + return null; + } + + /// + /// + /// + /// + /// + /// + /// + /// False for "caller try another codec"; true otherwise + private bool FetchTexture(IOSHttpRequest httpRequest, IOSHttpResponse httpResponse, UUID textureID, string format) + { + // m_log.DebugFormat("[GETTEXTURE]: {0} with requested format {1}", textureID, format); + AssetBase texture; + + if(!String.IsNullOrEmpty(m_RedirectURL)) + { + string textureUrl = m_RedirectURL + "?texture_id=" + textureID.ToString(); + m_log.Debug("[GETTEXTURE]: Redirecting texture request to " + textureUrl); + httpResponse.StatusCode = (int)OSHttpStatusCode.RedirectMovedPermanently; + httpResponse.RedirectLocation = textureUrl; + return true; + } + else // no redirect + { + texture = m_assetService.Get(textureID.ToString()); + if(texture != null) + { + if(texture.Type != (sbyte)AssetType.Texture) + { + httpResponse.StatusCode = (int)System.Net.HttpStatusCode.NotFound; + return true; + } + if(format == DefaultFormat) + { + WriteTextureData(httpRequest, httpResponse, texture, format); + return true; + } + else + { + AssetBase newTexture = new AssetBase(texture.ID + "-" + format, texture.Name, (sbyte)AssetType.Texture, texture.Metadata.CreatorID); + newTexture.Data = ConvertTextureData(texture, format); + if(newTexture.Data.Length == 0) + return false; // !!! Caller try another codec, please! + + newTexture.Flags = AssetFlags.Collectable; + newTexture.Temporary = true; + newTexture.Local = true; + WriteTextureData(httpRequest, httpResponse, newTexture, format); + return true; + } + } + } + + // not found + // m_log.Warn("[GETTEXTURE]: Texture " + textureID + " not found"); + httpResponse.StatusCode = (int)System.Net.HttpStatusCode.NotFound; + return true; + } + + private void WriteTextureData(IOSHttpRequest request, IOSHttpResponse response, AssetBase texture, string format) + { + string range = request.Headers.GetOne("Range"); + + if (!String.IsNullOrEmpty(range)) // JP2's only + { + // Range request + int start, end; + if (TryParseRange(range, out start, out end)) + { + // Before clamping start make sure we can satisfy it in order to avoid + // sending back the last byte instead of an error status + if (start >= texture.Data.Length) + { +// m_log.DebugFormat( +// "[GETTEXTURE]: Client requested range for texture {0} starting at {1} but texture has end of {2}", +// texture.ID, start, texture.Data.Length); + + // Stricly speaking, as per http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html, we should be sending back + // Requested Range Not Satisfiable (416) here. However, it appears that at least recent implementations + // of the Linden Lab viewer (3.2.1 and 3.3.4 and probably earlier), a viewer that has previously + // received a very small texture may attempt to fetch bytes from the server past the + // range of data that it received originally. Whether this happens appears to depend on whether + // the viewer's estimation of how large a request it needs to make for certain discard levels + // (http://wiki.secondlife.com/wiki/Image_System#Discard_Level_and_Mip_Mapping), chiefly discard + // level 2. If this estimate is greater than the total texture size, returning a RequestedRangeNotSatisfiable + // here will cause the viewer to treat the texture as bad and never display the full resolution + // However, if we return PartialContent (or OK) instead, the viewer will display that resolution. + +// response.StatusCode = (int)System.Net.HttpStatusCode.RequestedRangeNotSatisfiable; +// response.AddHeader("Content-Range", String.Format("bytes */{0}", texture.Data.Length)); +// response.StatusCode = (int)System.Net.HttpStatusCode.OK; + response.StatusCode = (int)System.Net.HttpStatusCode.PartialContent; + response.ContentType = texture.Metadata.ContentType; + } + else + { + // Handle the case where no second range value was given. This is equivalent to requesting + // the rest of the entity. + if (end == -1) + end = int.MaxValue; + + end = Utils.Clamp(end, 0, texture.Data.Length - 1); + start = Utils.Clamp(start, 0, end); + int len = end - start + 1; + +// m_log.Debug("Serving " + start + " to " + end + " of " + texture.Data.Length + " bytes for texture " + texture.ID); + + // Always return PartialContent, even if the range covered the entire data length + // We were accidentally sending back 404 before in this situation + // https://issues.apache.org/bugzilla/show_bug.cgi?id=51878 supports sending 206 even if the + // entire range is requested, and viewer 3.2.2 (and very probably earlier) seems fine with this. + // + // We also do not want to send back OK even if the whole range was satisfiable since this causes + // HTTP textures on at least Imprudence 1.4.0-beta2 to never display the final texture quality. +// if (end > maxEnd) +// response.StatusCode = (int)System.Net.HttpStatusCode.OK; +// else + response.StatusCode = (int)System.Net.HttpStatusCode.PartialContent; + + response.ContentLength = len; + response.ContentType = texture.Metadata.ContentType; + response.AddHeader("Content-Range", String.Format("bytes {0}-{1}/{2}", start, end, texture.Data.Length)); + + response.Body.Write(texture.Data, start, len); + } + } + else + { + m_log.Warn("[GETTEXTURE]: Malformed Range header: " + range); + response.StatusCode = (int)System.Net.HttpStatusCode.BadRequest; + } + } + else // JP2's or other formats + { + // Full content request + response.StatusCode = (int)System.Net.HttpStatusCode.OK; + response.ContentLength = texture.Data.Length; + if (format == DefaultFormat) + response.ContentType = texture.Metadata.ContentType; + else + response.ContentType = "image/" + format; + response.Body.Write(texture.Data, 0, texture.Data.Length); + } + +// if (response.StatusCode < 200 || response.StatusCode > 299) +// m_log.WarnFormat( +// "[GETTEXTURE]: For texture {0} requested range {1} responded {2} with content length {3} (actual {4})", +// texture.FullID, range, response.StatusCode, response.ContentLength, texture.Data.Length); +// else +// m_log.DebugFormat( +// "[GETTEXTURE]: For texture {0} requested range {1} responded {2} with content length {3} (actual {4})", +// texture.FullID, range, response.StatusCode, response.ContentLength, texture.Data.Length); + } + + /// + /// Parse a range header. + /// + /// + /// As per http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html, + /// this obeys range headers with two values (e.g. 533-4165) and no second value (e.g. 533-). + /// Where there is no value, -1 is returned. + /// FIXME: Need to cover the case where only a second value is specified (e.g. -4165), probably by returning -1 + /// for start. + /// + /// + /// Start of the range. Undefined if this was not a number. + /// End of the range. Will be -1 if no end specified. Undefined if there was a raw string but this was not a number. + private bool TryParseRange(string header, out int start, out int end) + { + start = end = 0; + + if (header.StartsWith("bytes=")) + { + string[] rangeValues = header.Substring(6).Split('-'); + + if (rangeValues.Length == 2) + { + if (!Int32.TryParse(rangeValues[0], out start)) + return false; + + string rawEnd = rangeValues[1]; + + if (rawEnd == "") + { + end = -1; + return true; + } + else if (Int32.TryParse(rawEnd, out end)) + { + return true; + } + } + } + + start = end = 0; + return false; + } + + private byte[] ConvertTextureData(AssetBase texture, string format) + { + m_log.DebugFormat("[GETTEXTURE]: Converting texture {0} to {1}", texture.ID, format); + byte[] data = new byte[0]; + + MemoryStream imgstream = new MemoryStream(); + Bitmap mTexture = null; + ManagedImage managedImage = null; + Image image = null; + + try + { + // Taking our jpeg2000 data, decoding it, then saving it to a byte array with regular data + // Decode image to System.Drawing.Image + if (OpenJPEG.DecodeToImage(texture.Data, out managedImage, out image) && image != null) + { + // Save to bitmap + mTexture = new Bitmap(image); + + using(EncoderParameters myEncoderParameters = new EncoderParameters()) + { + myEncoderParameters.Param[0] = new EncoderParameter(Encoder.Quality,95L); + + // Save bitmap to stream + ImageCodecInfo codec = GetEncoderInfo("image/" + format); + if (codec != null) + { + mTexture.Save(imgstream, codec, myEncoderParameters); + // Write the stream to a byte array for output + data = imgstream.ToArray(); + } + else + m_log.WarnFormat("[GETTEXTURE]: No such codec {0}", format); + } + } + } + catch (Exception e) + { + m_log.WarnFormat("[GETTEXTURE]: Unable to convert texture {0} to {1}: {2}", texture.ID, format, e.Message); + } + finally + { + // Reclaim memory, these are unmanaged resources + // If we encountered an exception, one or more of these will be null + if (mTexture != null) + mTexture.Dispose(); + + if (image != null) + image.Dispose(); + + if(managedImage != null) + managedImage.Clear(); + + if (imgstream != null) + imgstream.Dispose(); + } + + return data; + } + + // From msdn + private static ImageCodecInfo GetEncoderInfo(String mimeType) + { + ImageCodecInfo[] encoders; + encoders = ImageCodecInfo.GetImageEncoders(); + for (int j = 0; j < encoders.Length; ++j) + { + if (encoders[j].MimeType == mimeType) + return encoders[j]; + } + return null; + } + } +} 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; using OpenSim.Server.Handlers.Base; using OpenMetaverse; + namespace OpenSim.Capabilities.Handlers { public class GetTextureServerConnector : ServiceConnector @@ -65,7 +66,8 @@ namespace OpenSim.Capabilities.Handlers string rurl = serverConfig.GetString("GetTextureRedirectURL"); ; server.AddStreamHandler( - new GetTextureHandler("/CAPS/GetTexture/" /*+ UUID.Random() */, m_AssetService, "GetTexture", null, rurl)); + new GetTextureRobustHandler("/CAPS/GetTexture/", m_AssetService, "GetTexture", null, rurl)); } } -} \ No newline at end of file +} + 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; using OpenSim.Region.Framework.Scenes; using OpenSim.Tests.Common; +/* namespace OpenSim.Capabilities.Handlers.GetTexture.Tests { [TestFixture] @@ -59,4 +60,5 @@ namespace OpenSim.Capabilities.Handlers.GetTexture.Tests Assert.That(resp.StatusCode, Is.EqualTo((int)System.Net.HttpStatusCode.NotFound)); } } -} \ No newline at end of file +} +*/ 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 @@ using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -// General Information about an assembly is controlled through the following +// General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. [assembly: AssemblyTitle("OpenSim.Capabilities.Handlers")] @@ -14,8 +14,8 @@ using System.Runtime.InteropServices; [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from // COM, set the ComVisible attribute to true on that type. [assembly: ComVisible(false)] @@ -25,9 +25,9 @@ using System.Runtime.InteropServices; // Version information for an assembly consists of the following four values: // // Major Version -// Minor Version +// Minor Version // Build Number // Revision // -[assembly: AssemblyVersion("0.8.3.*")] +[assembly: AssemblyVersion(OpenSim.VersionInfo.AssemblyVersionNumber)] 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 @@ */ using System; -using System.Collections; -using System.Collections.Specialized; -using System.Drawing; -using System.Drawing.Imaging; using System.Reflection; -using System.IO; -using System.Web; using log4net; -using Nini.Config; using OpenMetaverse; -using OpenMetaverse.StructuredData; -using OpenMetaverse.Imaging; using OpenSim.Framework; using OpenSim.Framework.Capabilities; -using OpenSim.Framework.Servers; using OpenSim.Framework.Servers.HttpServer; -using OpenSim.Region.Framework.Interfaces; using OpenSim.Services.Interfaces; using Caps = OpenSim.Framework.Capabilities.Caps; @@ -50,17 +39,16 @@ namespace OpenSim.Capabilities.Handlers { public class UploadBakedTextureHandler { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private Caps m_HostCapsObj; private IAssetService m_assetService; - private bool m_persistBakedTextures; - public UploadBakedTextureHandler(Caps caps, IAssetService assetService, bool persistBakedTextures) + public UploadBakedTextureHandler(Caps caps, IAssetService assetService) { m_HostCapsObj = caps; m_assetService = assetService; - m_persistBakedTextures = persistBakedTextures; } /// @@ -81,7 +69,7 @@ namespace OpenSim.Capabilities.Handlers string uploaderPath = Util.RandomClass.Next(5000, 8000).ToString("0000"); BakedTextureUploader uploader = - new BakedTextureUploader(capsBase + uploaderPath, m_HostCapsObj.HttpListener); + new BakedTextureUploader(capsBase + uploaderPath, m_HostCapsObj.HttpListener, m_HostCapsObj.AgentID); uploader.OnUpLoad += BakedTextureUploaded; m_HostCapsObj.HttpListener.AddStreamHandler( @@ -117,13 +105,13 @@ namespace OpenSim.Capabilities.Handlers /// private void BakedTextureUploaded(UUID assetID, byte[] data) { -// m_log.DebugFormat("[UPLOAD BAKED TEXTURE HANDLER]: Received baked texture {0}", assetID.ToString()); + m_log.DebugFormat("[UPLOAD BAKED TEXTURE HANDLER]: Received baked texture {0}", assetID.ToString()); AssetBase asset; asset = new AssetBase(assetID, "Baked Texture", (sbyte)AssetType.Texture, m_HostCapsObj.AgentID.ToString()); asset.Data = data; asset.Temporary = true; - asset.Local = !m_persistBakedTextures; // Local assets aren't persisted, non-local are + asset.Local = true; m_assetService.Store(asset); } } @@ -137,12 +125,14 @@ namespace OpenSim.Capabilities.Handlers private string uploaderPath = String.Empty; private UUID newAssetID; private IHttpServer httpListener; + private UUID AgentId = UUID.Zero; - public BakedTextureUploader(string path, IHttpServer httpServer) + public BakedTextureUploader(string path, IHttpServer httpServer, UUID uUID) { newAssetID = UUID.Random(); uploaderPath = path; httpListener = httpServer; + AgentId = uUID; // m_log.InfoFormat("[CAPS] baked texture upload starting for {0}",newAssetID); } 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 server.AddStreamHandler(new RestStreamHandler( "POST", "/CAPS/UploadBakedTexture/", - new UploadBakedTextureHandler(caps, m_AssetService, true).UploadBakedTexture, + new UploadBakedTextureHandler(caps, m_AssetService).UploadBakedTexture, "UploadBakedTexture", "Upload Baked Texture Capability")); -- cgit v1.1