1
0

FetchLibDescHandler.cs 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342
  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. using System;
  28. using System.Collections.Generic;
  29. using System.Net;
  30. using System.Reflection;
  31. using System.Text;
  32. using log4net;
  33. using OpenMetaverse;
  34. using OpenMetaverse.StructuredData;
  35. using OpenSim.Framework;
  36. using OpenSim.Framework.Capabilities;
  37. using OpenSim.Framework.Servers.HttpServer;
  38. using OpenSim.Services.Interfaces;
  39. using OSDMap = OpenMetaverse.StructuredData.OSDMap;
  40. using OSDArray = OpenMetaverse.StructuredData.OSDArray;
  41. namespace OpenSim.Capabilities.Handlers
  42. {
  43. public class FetchLibDescHandler
  44. {
  45. private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
  46. private static readonly byte[] EmptyResponse = Util.UTF8NBGetbytes("<llsd><map><key>folders</key><array /></map></llsd>");
  47. private readonly ILibraryService m_LibraryService;
  48. private readonly UUID libOwner;
  49. private readonly IScene m_Scene;
  50. public FetchLibDescHandler(ILibraryService libService, IScene s)
  51. {
  52. m_LibraryService = libService;
  53. libOwner = m_LibraryService.LibraryRootFolder.Owner;
  54. m_Scene = s;
  55. }
  56. public void FetchRequest(IOSHttpRequest httpRequest, IOSHttpResponse httpResponse, ExpiringKey<UUID> BadRequests, UUID agentID)
  57. {
  58. //m_log.DebugFormat("[XXX]: FetchLibDescendentsRequest in {0}, {1}", (m_Scene == null) ? "none" : m_Scene.Name, request);
  59. if (m_LibraryService == null || m_LibraryService.LibraryRootFolder == null)
  60. {
  61. httpResponse.StatusCode = (int)HttpStatusCode.ServiceUnavailable;
  62. return;
  63. }
  64. httpResponse.StatusCode = (int)HttpStatusCode.OK;
  65. List<LLSDFetchInventoryDescendents> folders;
  66. List<UUID> bad_folders = new List<UUID>();
  67. try
  68. {
  69. OSDArray foldersrequested = null;
  70. OSD tmp = OSDParser.DeserializeLLSDXml(httpRequest.InputStream);
  71. httpRequest.InputStream.Dispose();
  72. OSDMap map = (OSDMap)tmp;
  73. if(map.TryGetValue("folders", out tmp) && tmp is OSDArray frtmp)
  74. foldersrequested = frtmp;
  75. if (foldersrequested is null || foldersrequested.Count == 0)
  76. {
  77. httpResponse.RawBuffer = EmptyResponse;
  78. return;
  79. }
  80. folders = new List<LLSDFetchInventoryDescendents>(foldersrequested.Count);
  81. for (int i = 0; i < foldersrequested.Count; i++)
  82. {
  83. OSDMap mfolder = foldersrequested[i] as OSDMap;
  84. UUID id = mfolder["folder_id"].AsUUID();
  85. if(BadRequests.ContainsKey(id))
  86. {
  87. bad_folders.Add(id);
  88. }
  89. else
  90. {
  91. LLSDFetchInventoryDescendents llsdRequest = new LLSDFetchInventoryDescendents();
  92. try
  93. {
  94. llsdRequest.folder_id = id;
  95. llsdRequest.owner_id = mfolder["owner_id"].AsUUID();
  96. llsdRequest.sort_order = mfolder["sort_order"].AsInteger();
  97. llsdRequest.fetch_folders = mfolder["fetch_folders"].AsBoolean();
  98. llsdRequest.fetch_items = mfolder["fetch_items"].AsBoolean();
  99. }
  100. catch (Exception e)
  101. {
  102. m_log.Debug("[WEB FETCH INV DESC HANDLER]: caught exception doing OSD deserialize" + e.Message);
  103. continue;
  104. }
  105. folders.Add(llsdRequest);
  106. }
  107. }
  108. foldersrequested = null;
  109. map.Clear();
  110. map = null;
  111. }
  112. catch (Exception e)
  113. {
  114. m_log.ErrorFormat("[FETCH LIB DESC]: fail parsing request: {0}", e.Message);
  115. httpResponse.RawBuffer = EmptyResponse;
  116. return;
  117. }
  118. if (folders is null || folders.Count == 0)
  119. {
  120. if(bad_folders.Count == 0)
  121. {
  122. httpResponse.RawBuffer = EmptyResponse;
  123. return;
  124. }
  125. osUTF8 osu = OSUTF8Cached.Acquire();
  126. osu.AppendASCII("[FETCH LIB DESC HANDLER]: Unable to fetch folders:");
  127. int limit = 5;
  128. int count = 0;
  129. foreach (UUID bad in bad_folders)
  130. {
  131. if (BadRequests.ContainsKey(bad))
  132. continue;
  133. osu.Append((byte)' ');
  134. osu.AppendASCII(bad.ToString());
  135. ++count;
  136. if (--limit < 0)
  137. break;
  138. }
  139. if(count > 0)
  140. {
  141. if (limit < 0)
  142. osu.AppendASCII(" ...");
  143. m_log.Warn(osu.ToString());
  144. }
  145. osu.Clear();
  146. osu.AppendASCII("<llsd><map><key>folders</key><array /></map><map><key>bad_folders</key><array>");
  147. foreach (UUID bad in bad_folders)
  148. {
  149. osu.AppendASCII("<map><key>folder_id</key><uuid>");
  150. osu.AppendASCII(bad.ToString());
  151. osu.AppendASCII("</uuid><key>error</key><string>Unknown</string></map>");
  152. }
  153. osu.AppendASCII("</array></map></llsd>");
  154. httpResponse.RawBuffer = OSUTF8Cached.GetArrayAndRelease(osu);
  155. return;
  156. }
  157. UUID requester = folders[0].owner_id;
  158. List<InventoryCollection> invcollSet = Fetch(folders, bad_folders);
  159. //m_log.DebugFormat("[XXX]: Got {0} folders from a request of {1}", invcollSet.Count, folders.Count);
  160. int invcollSetCount = 0;
  161. if (invcollSet != null)
  162. invcollSetCount = invcollSet.Count;
  163. osUTF8 lastresponse = LLSDxmlEncode2.Start();
  164. if (invcollSetCount > 0)
  165. {
  166. lastresponse.AppendASCII("<map><key>folders</key><array>");
  167. int i = 0;
  168. InventoryCollection thiscoll;
  169. for (i = 0; i < invcollSetCount; i++)
  170. {
  171. thiscoll = invcollSet[i];
  172. invcollSet[i] = null;
  173. LLSDxmlEncode2.AddMap(lastresponse);
  174. LLSDxmlEncode2.AddElem_folder_id(thiscoll.FolderID, lastresponse);
  175. LLSDxmlEncode2.AddElem_agent_id(agentID, lastresponse);
  176. LLSDxmlEncode2.AddElem_owner_id(thiscoll.OwnerID, lastresponse);
  177. LLSDxmlEncode2.AddElem("descendents", thiscoll.Descendents, lastresponse);
  178. LLSDxmlEncode2.AddElem_version(thiscoll.Version, lastresponse);
  179. if (thiscoll.Folders == null || thiscoll.Folders.Count == 0)
  180. LLSDxmlEncode2.AddEmptyArray("categories", lastresponse);
  181. else
  182. {
  183. LLSDxmlEncode2.AddArray("categories", lastresponse);
  184. foreach (InventoryFolderBase invFolder in thiscoll.Folders)
  185. {
  186. LLSDxmlEncode2.AddMap(lastresponse);
  187. LLSDxmlEncode2.AddElem_category_id(invFolder.ID, lastresponse);
  188. LLSDxmlEncode2.AddElem_parent_id(invFolder.ParentID, lastresponse);
  189. LLSDxmlEncode2.AddElem_name(invFolder.Name, lastresponse);
  190. LLSDxmlEncode2.AddElem("type_default", invFolder.Type, lastresponse);
  191. LLSDxmlEncode2.AddElem_version( invFolder.Version, lastresponse);
  192. LLSDxmlEncode2.AddEndMap(lastresponse);
  193. }
  194. LLSDxmlEncode2.AddEndArray(lastresponse);
  195. }
  196. if (thiscoll.Items == null || thiscoll.Items.Count == 0)
  197. LLSDxmlEncode2.AddEmptyArray("items", lastresponse);
  198. else
  199. {
  200. LLSDxmlEncode2.AddArray("items", lastresponse);
  201. foreach (InventoryItemBase invItem in thiscoll.Items)
  202. {
  203. invItem.ToLLSDxml(lastresponse);
  204. }
  205. LLSDxmlEncode2.AddEndArray(lastresponse);
  206. }
  207. LLSDxmlEncode2.AddEndMap(lastresponse);
  208. invcollSet[i] = null;
  209. }
  210. LLSDxmlEncode2.AddEndArrayAndMap(lastresponse);
  211. }
  212. else
  213. {
  214. lastresponse.AppendASCII("<map><key>folders</key><array /></map>");
  215. }
  216. if (bad_folders.Count > 0)
  217. {
  218. lastresponse.AppendASCII("<map><key>bad_folders</key><array>");
  219. foreach (UUID bad in bad_folders)
  220. {
  221. BadRequests.Add(bad);
  222. lastresponse.AppendASCII("<map><key>folder_id</key><uuid>");
  223. lastresponse.AppendASCII(bad.ToString());
  224. lastresponse.AppendASCII("</uuid><key>error</key><string>Unknown</string></map>");
  225. }
  226. lastresponse.AppendASCII("</array></map>");
  227. StringBuilder sb = osStringBuilderCache.Acquire();
  228. sb.Append("[WEB FETCH INV DESC HANDLER]: Unable to fetch folders owned by ");
  229. sb.Append(requester.ToString());
  230. sb.Append(" :");
  231. int limit = 9;
  232. foreach (UUID bad in bad_folders)
  233. {
  234. sb.Append(' ');
  235. sb.Append(bad.ToString());
  236. if(--limit < 0)
  237. break;
  238. }
  239. if(limit < 0)
  240. sb.Append(" ...");
  241. m_log.Warn(osStringBuilderCache.GetStringAndRelease(sb));
  242. }
  243. httpResponse.RawBuffer = LLSDxmlEncode2.EndToBytes(lastresponse);
  244. }
  245. private List<InventoryCollection> Fetch(List<LLSDFetchInventoryDescendents> fetchFolders, List<UUID> bad_folders)
  246. {
  247. //m_log.DebugFormat(
  248. // "[FETCH LIB DESC HANDLER]: Fetching {0} folders", fetchFolders.Count);
  249. // FIXME MAYBE: We're not handling sortOrder!
  250. int cntr = fetchFolders.Count;
  251. List<InventoryCollection> result = new List<InventoryCollection>(cntr);
  252. List<LLSDFetchInventoryDescendents> libFolders = new List<LLSDFetchInventoryDescendents>(cntr);
  253. HashSet<UUID> libIDs = new HashSet<UUID>();
  254. // Filter folder Zero right here. Some viewers (Firestorm) send request for folder Zero, which doesn't make sense
  255. // and can kill the sim (all root folders have parent_id Zero)
  256. // send something.
  257. bool doneZeroID = false;
  258. foreach(LLSDFetchInventoryDescendents f in fetchFolders)
  259. {
  260. if (f.folder_id.IsZero())
  261. {
  262. if(doneZeroID)
  263. continue;
  264. doneZeroID = true;
  265. InventoryCollection Collection = new InventoryCollection()
  266. {
  267. OwnerID = f.owner_id,
  268. Version = -1,
  269. FolderID = f.folder_id,
  270. Descendents = 0
  271. };
  272. result.Add(Collection);
  273. continue;
  274. }
  275. if(f.owner_id.Equals(libOwner))
  276. {
  277. if(libIDs.Contains(f.folder_id))
  278. continue;
  279. libIDs.Add(f.folder_id);
  280. libFolders.Add(f);
  281. continue;
  282. }
  283. }
  284. if (libFolders.Count > 0)
  285. {
  286. foreach (LLSDFetchInventoryDescendents f in libFolders)
  287. {
  288. InventoryFolderImpl fold = m_LibraryService.LibraryRootFolder.FindFolder(f.folder_id);
  289. if (fold != null)
  290. {
  291. InventoryCollection Collection = new InventoryCollection()
  292. {
  293. Folders = fold.RequestListOfFolders(),
  294. Items = fold.RequestListOfItems(),
  295. OwnerID = m_LibraryService.LibraryRootFolder.Owner,
  296. FolderID = f.folder_id,
  297. Version = fold.Version
  298. };
  299. Collection.Descendents = Collection.Items.Count + Collection.Folders.Count;
  300. result.Add(Collection);
  301. //m_log.DebugFormat("[XXX]: Added libfolder {0} ({1}) {2}", ret.Collection.FolderID, ret.Collection.OwnerID);
  302. }
  303. else
  304. bad_folders.Add(f.folder_id);
  305. }
  306. }
  307. return result;
  308. }
  309. }
  310. }