diff options
Diffstat (limited to 'OpenSim/Capabilities/Handlers/GetMesh')
-rw-r--r-- | OpenSim/Capabilities/Handlers/GetMesh/GetMeshHandler.cs | 194 |
1 files changed, 164 insertions, 30 deletions
diff --git a/OpenSim/Capabilities/Handlers/GetMesh/GetMeshHandler.cs b/OpenSim/Capabilities/Handlers/GetMesh/GetMeshHandler.cs index 6b67da1..7fcc798 100644 --- a/OpenSim/Capabilities/Handlers/GetMesh/GetMeshHandler.cs +++ b/OpenSim/Capabilities/Handlers/GetMesh/GetMeshHandler.cs | |||
@@ -44,26 +44,64 @@ namespace OpenSim.Capabilities.Handlers | |||
44 | public class GetMeshHandler : BaseStreamHandler | 44 | public class GetMeshHandler : BaseStreamHandler |
45 | { | 45 | { |
46 | private static readonly ILog m_log = | 46 | private static readonly ILog m_log = |
47 | LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 47 | LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
48 | |||
48 | private IAssetService m_assetService; | 49 | private IAssetService m_assetService; |
49 | 50 | ||
50 | // TODO: Change this to a config option | 51 | public const string DefaultFormat = "vnd.ll.mesh"; |
51 | private string m_RedirectURL = null; | 52 | |
52 | 53 | public GetMeshHandler(IAssetService assService) | |
53 | public GetMeshHandler(string path, IAssetService assService, string name, string description, string redirectURL) | ||
54 | : base("GET", path, name, description) | ||
55 | { | 54 | { |
56 | m_assetService = assService; | 55 | m_assetService = assService; |
57 | m_RedirectURL = redirectURL; | 56 | m_RedirectURL = redirectURL; |
58 | if (m_RedirectURL != null && !m_RedirectURL.EndsWith("/")) | 57 | if (m_RedirectURL != null && !m_RedirectURL.EndsWith("/")) |
59 | m_RedirectURL += "/"; | 58 | m_RedirectURL += "/"; |
60 | } | 59 | } |
60 | public Hashtable Handle(Hashtable request) | ||
61 | { | ||
62 | Hashtable ret = new Hashtable(); | ||
63 | ret["int_response_code"] = (int)System.Net.HttpStatusCode.NotFound; | ||
64 | ret["content_type"] = "text/plain"; | ||
65 | ret["keepalive"] = false; | ||
66 | ret["reusecontext"] = false; | ||
67 | ret["int_bytes"] = 0; | ||
68 | ret["int_lod"] = 0; | ||
69 | string MeshStr = (string)request["mesh_id"]; | ||
70 | |||
71 | |||
72 | //m_log.DebugFormat("[GETMESH]: called {0}", MeshStr); | ||
73 | |||
74 | if (m_assetService == null) | ||
75 | { | ||
76 | m_log.Error("[GETMESH]: Cannot fetch mesh " + MeshStr + " without an asset service"); | ||
77 | } | ||
78 | |||
79 | UUID meshID; | ||
80 | if (!String.IsNullOrEmpty(MeshStr) && UUID.TryParse(MeshStr, out meshID)) | ||
81 | { | ||
82 | // m_log.DebugFormat("[GETMESH]: Received request for mesh id {0}", meshID); | ||
83 | |||
84 | |||
85 | ret = ProcessGetMesh(request, UUID.Zero, null); | ||
86 | |||
87 | |||
88 | } | ||
89 | else | ||
90 | { | ||
91 | m_log.Warn("[GETMESH]: Failed to parse a mesh_id from GetMesh request: " + (string)request["uri"]); | ||
92 | } | ||
61 | 93 | ||
62 | protected override byte[] ProcessRequest(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) | 94 | |
95 | return ret; | ||
96 | } | ||
97 | public Hashtable ProcessGetMesh(Hashtable request, UUID AgentId, Caps cap) | ||
63 | { | 98 | { |
64 | // Try to parse the texture ID from the request URL | 99 | // Try to parse the texture ID from the request URL |
65 | NameValueCollection query = HttpUtility.ParseQueryString(httpRequest.Url.Query); | 100 | NameValueCollection query = HttpUtility.ParseQueryString(httpRequest.Url.Query); |
66 | string textureStr = query.GetOne("mesh_id"); | 101 | string textureStr = query.GetOne("mesh_id"); |
102 | responsedata["reusecontext"] = false; | ||
103 | responsedata["int_lod"] = 0; | ||
104 | responsedata["int_bytes"] = 0; | ||
67 | 105 | ||
68 | if (m_assetService == null) | 106 | if (m_assetService == null) |
69 | { | 107 | { |
@@ -160,40 +198,121 @@ namespace OpenSim.Capabilities.Handlers | |||
160 | // sending back the last byte instead of an error status | 198 | // sending back the last byte instead of an error status |
161 | if (start >= texture.Data.Length) | 199 | if (start >= texture.Data.Length) |
162 | { | 200 | { |
163 | response.StatusCode = (int)System.Net.HttpStatusCode.PartialContent; | ||
164 | response.ContentType = texture.Metadata.ContentType; | ||
165 | } | ||
166 | else | ||
167 | { | ||
168 | // Handle the case where no second range value was given. This is equivalent to requesting | ||
169 | // the rest of the entity. | ||
170 | if (end == -1) | ||
171 | end = int.MaxValue; | ||
172 | 201 | ||
173 | end = Utils.Clamp(end, 0, texture.Data.Length - 1); | 202 | Hashtable headers = new Hashtable(); |
174 | start = Utils.Clamp(start, 0, end); | 203 | responsedata["headers"] = headers; |
175 | int len = end - start + 1; | 204 | |
205 | string range = String.Empty; | ||
206 | |||
207 | if (((Hashtable)request["headers"])["range"] != null) | ||
208 | range = (string)((Hashtable)request["headers"])["range"]; | ||
176 | 209 | ||
177 | if (0 == start && len == texture.Data.Length) | 210 | else if (((Hashtable)request["headers"])["Range"] != null) |
211 | range = (string)((Hashtable)request["headers"])["Range"]; | ||
212 | |||
213 | if (!String.IsNullOrEmpty(range)) // Mesh Asset LOD // Physics | ||
178 | { | 214 | { |
179 | response.StatusCode = (int)System.Net.HttpStatusCode.OK; | 215 | // Range request |
216 | int start, end; | ||
217 | if (TryParseRange(range, out start, out end)) | ||
218 | { | ||
219 | // Before clamping start make sure we can satisfy it in order to avoid | ||
220 | // sending back the last byte instead of an error status | ||
221 | if (start >= mesh.Data.Length) | ||
222 | { | ||
223 | responsedata["int_response_code"] = 404; //501; //410; //404; | ||
224 | responsedata["content_type"] = "text/plain"; | ||
225 | responsedata["keepalive"] = false; | ||
226 | responsedata["str_response_string"] = "This range doesnt exist."; | ||
227 | responsedata["reusecontext"] = false; | ||
228 | responsedata["int_lod"] = 3; | ||
229 | return responsedata; | ||
230 | } | ||
231 | else | ||
232 | { | ||
233 | end = Utils.Clamp(end, 0, mesh.Data.Length - 1); | ||
234 | start = Utils.Clamp(start, 0, end); | ||
235 | int len = end - start + 1; | ||
236 | |||
237 | //m_log.Debug("Serving " + start + " to " + end + " of " + texture.Data.Length + " bytes for texture " + texture.ID); | ||
238 | |||
239 | if (start > 20000) | ||
240 | { | ||
241 | responsedata["int_lod"] = 3; | ||
242 | } | ||
243 | else if (start < 4097) | ||
244 | { | ||
245 | responsedata["int_lod"] = 1; | ||
246 | } | ||
247 | else | ||
248 | { | ||
249 | responsedata["int_lod"] = 2; | ||
250 | } | ||
251 | |||
252 | |||
253 | if (start == 0 && len == mesh.Data.Length) // well redudante maybe | ||
254 | { | ||
255 | responsedata["int_response_code"] = (int) System.Net.HttpStatusCode.OK; | ||
256 | responsedata["bin_response_data"] = mesh.Data; | ||
257 | responsedata["int_bytes"] = mesh.Data.Length; | ||
258 | responsedata["reusecontext"] = false; | ||
259 | responsedata["int_lod"] = 3; | ||
260 | |||
261 | } | ||
262 | else | ||
263 | { | ||
264 | responsedata["int_response_code"] = | ||
265 | (int) System.Net.HttpStatusCode.PartialContent; | ||
266 | headers["Content-Range"] = String.Format("bytes {0}-{1}/{2}", start, end, | ||
267 | mesh.Data.Length); | ||
268 | |||
269 | byte[] d = new byte[len]; | ||
270 | Array.Copy(mesh.Data, start, d, 0, len); | ||
271 | responsedata["bin_response_data"] = d; | ||
272 | responsedata["int_bytes"] = len; | ||
273 | responsedata["reusecontext"] = false; | ||
274 | } | ||
275 | } | ||
276 | } | ||
277 | else | ||
278 | { | ||
279 | m_log.Warn("[GETMESH]: Failed to parse a range from GetMesh request, sending full asset: " + (string)request["uri"]); | ||
280 | responsedata["str_response_string"] = Convert.ToBase64String(mesh.Data); | ||
281 | responsedata["content_type"] = "application/vnd.ll.mesh"; | ||
282 | responsedata["int_response_code"] = 200; | ||
283 | responsedata["reusecontext"] = false; | ||
284 | responsedata["int_lod"] = 3; | ||
285 | } | ||
180 | } | 286 | } |
181 | else | 287 | else |
182 | { | 288 | { |
183 | response.StatusCode = (int)System.Net.HttpStatusCode.PartialContent; | 289 | responsedata["str_response_string"] = Convert.ToBase64String(mesh.Data); |
184 | response.AddHeader("Content-Range", String.Format("bytes {0}-{1}/{2}", start, end, texture.Data.Length)); | 290 | responsedata["content_type"] = "application/vnd.ll.mesh"; |
291 | responsedata["int_response_code"] = 200; | ||
292 | responsedata["reusecontext"] = false; | ||
293 | responsedata["int_lod"] = 3; | ||
185 | } | 294 | } |
186 | 295 | } | |
187 | response.ContentLength = len; | 296 | else |
188 | response.ContentType = "application/vnd.ll.mesh"; | 297 | { |
189 | 298 | responsedata["int_response_code"] = 404; //501; //410; //404; | |
190 | response.Body.Write(texture.Data, start, len); | 299 | responsedata["content_type"] = "text/plain"; |
300 | responsedata["keepalive"] = false; | ||
301 | responsedata["str_response_string"] = "Unfortunately, this asset isn't a mesh."; | ||
302 | responsedata["reusecontext"] = false; | ||
303 | responsedata["int_lod"] = 1; | ||
304 | return responsedata; | ||
191 | } | 305 | } |
192 | } | 306 | } |
193 | else | 307 | else |
194 | { | 308 | { |
195 | m_log.Warn("[GETMESH]: Malformed Range header: " + range); | 309 | responsedata["int_response_code"] = 404; //501; //410; //404; |
196 | response.StatusCode = (int)System.Net.HttpStatusCode.BadRequest; | 310 | responsedata["content_type"] = "text/plain"; |
311 | responsedata["keepalive"] = false; | ||
312 | responsedata["str_response_string"] = "Your Mesh wasn't found. Sorry!"; | ||
313 | responsedata["reusecontext"] = false; | ||
314 | responsedata["int_lod"] = 0; | ||
315 | return responsedata; | ||
197 | } | 316 | } |
198 | } | 317 | } |
199 | else | 318 | else |
@@ -249,5 +368,20 @@ namespace OpenSim.Capabilities.Handlers | |||
249 | start = end = 0; | 368 | start = end = 0; |
250 | return false; | 369 | return false; |
251 | } | 370 | } |
371 | private bool TryParseRange(string header, out int start, out int end) | ||
372 | { | ||
373 | if (header.StartsWith("bytes=")) | ||
374 | { | ||
375 | string[] rangeValues = header.Substring(6).Split('-'); | ||
376 | if (rangeValues.Length == 2) | ||
377 | { | ||
378 | if (Int32.TryParse(rangeValues[0], out start) && Int32.TryParse(rangeValues[1], out end)) | ||
379 | return true; | ||
380 | } | ||
381 | } | ||
382 | |||
383 | start = end = 0; | ||
384 | return false; | ||
385 | } | ||
252 | } | 386 | } |
253 | } \ No newline at end of file | 387 | } \ No newline at end of file |