OpenSim
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros
GetMeshHandler.cs
Go to the documentation of this file.
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 
28 using System;
29 using System.Collections;
30 using System.Collections.Specialized;
31 using System.Reflection;
32 using System.IO;
33 using System.Web;
34 using log4net;
35 using Nini.Config;
36 using OpenMetaverse;
37 using OpenMetaverse.StructuredData;
38 using OpenSim.Framework;
39 using OpenSim.Framework.Servers;
40 using OpenSim.Framework.Servers.HttpServer;
41 using OpenSim.Services.Interfaces;
43 
44 
45 
46 
47 namespace OpenSim.Capabilities.Handlers
48 {
49  public class GetMeshHandler
50  {
51  private static readonly ILog m_log =
52  LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
53 
54  private IAssetService m_assetService;
55 
56  public const string DefaultFormat = "vnd.ll.mesh";
57 
58  public GetMeshHandler(IAssetService assService)
59  {
60  m_assetService = assService;
61  }
62  public Hashtable Handle(Hashtable request)
63  {
64  Hashtable ret = new Hashtable();
65  ret["int_response_code"] = (int)System.Net.HttpStatusCode.NotFound;
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);
75 
76  if (m_assetService == null)
77  {
78  m_log.Error("[GETMESH]: Cannot fetch mesh " + MeshStr + " without an asset service");
79  }
80 
81  UUID meshID;
82  if (!String.IsNullOrEmpty(MeshStr) && UUID.TryParse(MeshStr, out meshID))
83  {
84  // m_log.DebugFormat("[GETMESH]: Received request for mesh id {0}", meshID);
85 
86 
87  ret = ProcessGetMesh(request, UUID.Zero, null);
88 
89 
90  }
91  else
92  {
93  m_log.Warn("[GETMESH]: Failed to parse a mesh_id from GetMesh request: " + (string)request["uri"]);
94  }
95 
96 
97  return ret;
98  }
99  public Hashtable ProcessGetMesh(Hashtable request, UUID AgentId, Caps cap)
100  {
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;
111 
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))
117  {
118  if (m_assetService == null)
119  {
120  responsedata["int_response_code"] = 404; //501; //410; //404;
121  responsedata["content_type"] = "text/plain";
122  responsedata["keepalive"] = false;
123  responsedata["str_response_string"] = "The asset service is unavailable. So is your mesh.";
124  responsedata["reusecontext"] = false;
125  return responsedata;
126  }
127 
128  AssetBase mesh = m_assetService.Get(meshID.ToString());
129 
130  if (mesh != null)
131  {
132  if (mesh.Type == (SByte)AssetType.Mesh)
133  {
134 
135  Hashtable headers = new Hashtable();
136  responsedata["headers"] = headers;
137 
138  string range = String.Empty;
139 
140  if (((Hashtable)request["headers"])["range"] != null)
141  range = (string)((Hashtable)request["headers"])["range"];
142 
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
147  {
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  }
219  }
220  else
221  {
222  responsedata["str_response_string"] = Convert.ToBase64String(mesh.Data);
223  responsedata["content_type"] = "application/vnd.ll.mesh";
224  responsedata["int_response_code"] = 200;
225  responsedata["reusecontext"] = false;
226  responsedata["int_lod"] = 3;
227  }
228  }
229  // Optionally add additional mesh types here
230  else
231  {
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;
239  }
240  }
241  else
242  {
243  responsedata["int_response_code"] = 404; //501; //410; //404;
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;
250  }
251  }
252 
253  return responsedata;
254  }
255  private bool TryParseRange(string header, out int start, out int end)
256  {
257  if (header.StartsWith("bytes="))
258  {
259  string[] rangeValues = header.Substring(6).Split('-');
260  if (rangeValues.Length == 2)
261  {
262  if (Int32.TryParse(rangeValues[0], out start) && Int32.TryParse(rangeValues[1], out end))
263  return true;
264  }
265  }
266 
267  start = end = 0;
268  return false;
269  }
270  }
271 }
Hashtable ProcessGetMesh(Hashtable request, UUID AgentId, Caps cap)
OpenSim.Framework.Capabilities.Caps Caps
sbyte Type
(sbyte) AssetType enum
Definition: AssetBase.cs:198
Asset class. All Assets are reference by this class or a class derived from this class ...
Definition: AssetBase.cs:49
OpenSim.Framework.Capabilities.Caps Caps