aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Capabilities/Handlers/GetMesh/GetMeshHandler.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Capabilities/Handlers/GetMesh/GetMeshHandler.cs')
-rw-r--r--OpenSim/Capabilities/Handlers/GetMesh/GetMeshHandler.cs187
1 files changed, 153 insertions, 34 deletions
diff --git a/OpenSim/Capabilities/Handlers/GetMesh/GetMeshHandler.cs b/OpenSim/Capabilities/Handlers/GetMesh/GetMeshHandler.cs
index ec574a3..7fcc798 100644
--- a/OpenSim/Capabilities/Handlers/GetMesh/GetMeshHandler.cs
+++ b/OpenSim/Capabilities/Handlers/GetMesh/GetMeshHandler.cs
@@ -25,25 +25,23 @@
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */ 26 */
27 27
28using System;
29using System.Collections;
30using System.Collections.Specialized;
31using System.Reflection;
32using System.IO;
33using System.Web;
34using log4net; 28using log4net;
35using Nini.Config;
36using OpenMetaverse; 29using OpenMetaverse;
37using OpenMetaverse.StructuredData; 30using OpenMetaverse.Imaging;
38using OpenSim.Framework; 31using OpenSim.Framework;
39using OpenSim.Framework.Servers;
40using OpenSim.Framework.Servers.HttpServer; 32using OpenSim.Framework.Servers.HttpServer;
41using OpenSim.Services.Interfaces; 33using OpenSim.Services.Interfaces;
42using Caps = OpenSim.Framework.Capabilities.Caps; 34using System;
35using System.Collections.Specialized;
36using System.Drawing;
37using System.Drawing.Imaging;
38using System.IO;
39using System.Reflection;
40using System.Web;
43 41
44namespace OpenSim.Capabilities.Handlers 42namespace OpenSim.Capabilities.Handlers
45{ 43{
46 public class GetMeshHandler 44 public class GetMeshHandler : BaseStreamHandler
47 { 45 {
48 private static readonly ILog m_log = 46 private static readonly ILog m_log =
49 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 47 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
@@ -55,6 +53,9 @@ namespace OpenSim.Capabilities.Handlers
55 public GetMeshHandler(IAssetService assService) 53 public GetMeshHandler(IAssetService assService)
56 { 54 {
57 m_assetService = assService; 55 m_assetService = assService;
56 m_RedirectURL = redirectURL;
57 if (m_RedirectURL != null && !m_RedirectURL.EndsWith("/"))
58 m_RedirectURL += "/";
58 } 59 }
59 public Hashtable Handle(Hashtable request) 60 public Hashtable Handle(Hashtable request)
60 { 61 {
@@ -95,38 +96,107 @@ namespace OpenSim.Capabilities.Handlers
95 } 96 }
96 public Hashtable ProcessGetMesh(Hashtable request, UUID AgentId, Caps cap) 97 public Hashtable ProcessGetMesh(Hashtable request, UUID AgentId, Caps cap)
97 { 98 {
98 Hashtable responsedata = new Hashtable(); 99 // Try to parse the texture ID from the request URL
99 responsedata["int_response_code"] = 400; //501; //410; //404; 100 NameValueCollection query = HttpUtility.ParseQueryString(httpRequest.Url.Query);
100 responsedata["content_type"] = "text/plain"; 101 string textureStr = query.GetOne("mesh_id");
101 responsedata["keepalive"] = false;
102 responsedata["str_response_string"] = "Request wasn't what was expected";
103 responsedata["reusecontext"] = false; 102 responsedata["reusecontext"] = false;
104 responsedata["int_lod"] = 0; 103 responsedata["int_lod"] = 0;
105 responsedata["int_bytes"] = 0; 104 responsedata["int_bytes"] = 0;
106 105
107 string meshStr = string.Empty; 106 if (m_assetService == null)
108 107 {
109 if (request.ContainsKey("mesh_id")) 108 m_log.Error("[GETMESH]: Cannot fetch mesh " + textureStr + " without an asset service");
110 meshStr = request["mesh_id"].ToString(); 109 httpResponse.StatusCode = (int)System.Net.HttpStatusCode.NotFound;
110 }
111 111
112 UUID meshID = UUID.Zero; 112 UUID meshID;
113 if (!String.IsNullOrEmpty(meshStr) && UUID.TryParse(meshStr, out meshID)) 113 if (!String.IsNullOrEmpty(textureStr) && UUID.TryParse(textureStr, out meshID))
114 { 114 {
115 if (m_assetService == null) 115 // OK, we have an array with preferred formats, possibly with only one entry
116
117 httpResponse.StatusCode = (int)System.Net.HttpStatusCode.NotFound;
118 AssetBase mesh;
119
120 if (!String.IsNullOrEmpty(m_RedirectURL))
116 { 121 {
117 responsedata["int_response_code"] = 404; //501; //410; //404; 122 // Only try to fetch locally cached meshes. Misses are redirected
118 responsedata["content_type"] = "text/plain"; 123 mesh = m_assetService.GetCached(meshID.ToString());
119 responsedata["keepalive"] = false; 124
120 responsedata["str_response_string"] = "The asset service is unavailable. So is your mesh."; 125 if (mesh != null)
121 responsedata["reusecontext"] = false; 126 {
122 return responsedata; 127 if (mesh.Type != (sbyte)AssetType.Mesh)
128 {
129 httpResponse.StatusCode = (int)System.Net.HttpStatusCode.NotFound;
130 }
131 WriteMeshData(httpRequest, httpResponse, mesh);
132 }
133 else
134 {
135 string textureUrl = m_RedirectURL + "?mesh_id="+ meshID.ToString();
136 m_log.Debug("[GETMESH]: Redirecting mesh request to " + textureUrl);
137 httpResponse.StatusCode = (int)OSHttpStatusCode.RedirectMovedPermanently;
138 httpResponse.RedirectLocation = textureUrl;
139 return null;
140 }
123 } 141 }
142 else // no redirect
143 {
144 // try the cache
145 mesh = m_assetService.GetCached(meshID.ToString());
124 146
125 AssetBase mesh = m_assetService.Get(meshID.ToString()); 147 if (mesh == null)
148 {
149 // Fetch locally or remotely. Misses return a 404
150 mesh = m_assetService.Get(meshID.ToString());
151
152 if (mesh != null)
153 {
154 if (mesh.Type != (sbyte)AssetType.Mesh)
155 {
156 httpResponse.StatusCode = (int)System.Net.HttpStatusCode.NotFound;
157 return null;
158 }
159 WriteMeshData(httpRequest, httpResponse, mesh);
160 return null;
161 }
162 }
163 else // it was on the cache
164 {
165 if (mesh.Type != (sbyte)AssetType.Mesh)
166 {
167 httpResponse.StatusCode = (int)System.Net.HttpStatusCode.NotFound;
168 return null;
169 }
170 WriteMeshData(httpRequest, httpResponse, mesh);
171 return null;
172 }
173 }
126 174
127 if (mesh != null) 175 // not found
176 httpResponse.StatusCode = (int)System.Net.HttpStatusCode.NotFound;
177 return null;
178 }
179 else
180 {
181 m_log.Warn("[GETTEXTURE]: Failed to parse a mesh_id from GetMesh request: " + httpRequest.Url);
182 }
183
184 return null;
185 }
186
187 private void WriteMeshData(IOSHttpRequest request, IOSHttpResponse response, AssetBase texture)
188 {
189 string range = request.Headers.GetOne("Range");
190
191 if (!String.IsNullOrEmpty(range))
192 {
193 // Range request
194 int start, end;
195 if (TryParseRange(range, out start, out end))
128 { 196 {
129 if (mesh.Type == (SByte)AssetType.Mesh) 197 // Before clamping start make sure we can satisfy it in order to avoid
198 // sending back the last byte instead of an error status
199 if (start >= texture.Data.Length)
130 { 200 {
131 201
132 Hashtable headers = new Hashtable(); 202 Hashtable headers = new Hashtable();
@@ -223,7 +293,6 @@ namespace OpenSim.Capabilities.Handlers
223 responsedata["int_lod"] = 3; 293 responsedata["int_lod"] = 3;
224 } 294 }
225 } 295 }
226 // Optionally add additional mesh types here
227 else 296 else
228 { 297 {
229 responsedata["int_response_code"] = 404; //501; //410; //404; 298 responsedata["int_response_code"] = 404; //501; //410; //404;
@@ -246,8 +315,58 @@ namespace OpenSim.Capabilities.Handlers
246 return responsedata; 315 return responsedata;
247 } 316 }
248 } 317 }
318 else
319 {
320 // Full content request
321 response.StatusCode = (int)System.Net.HttpStatusCode.OK;
322 response.ContentLength = texture.Data.Length;
323 response.ContentType = "application/vnd.ll.mesh";
324 response.Body.Write(texture.Data, 0, texture.Data.Length);
325 }
326 }
249 327
250 return responsedata; 328 /// <summary>
329 /// Parse a range header.
330 /// </summary>
331 /// <remarks>
332 /// As per http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html,
333 /// this obeys range headers with two values (e.g. 533-4165) and no second value (e.g. 533-).
334 /// Where there is no value, -1 is returned.
335 /// FIXME: Need to cover the case where only a second value is specified (e.g. -4165), probably by returning -1
336 /// for start.</remarks>
337 /// <returns></returns>
338 /// <param name='header'></param>
339 /// <param name='start'>Start of the range. Undefined if this was not a number.</param>
340 /// <param name='end'>End of the range. Will be -1 if no end specified. Undefined if there was a raw string but this was not a number.</param>
341 private bool TryParseRange(string header, out int start, out int end)
342 {
343 start = end = 0;
344
345 if (header.StartsWith("bytes="))
346 {
347 string[] rangeValues = header.Substring(6).Split('-');
348
349 if (rangeValues.Length == 2)
350 {
351 if (!Int32.TryParse(rangeValues[0], out start))
352 return false;
353
354 string rawEnd = rangeValues[1];
355
356 if (rawEnd == "")
357 {
358 end = -1;
359 return true;
360 }
361 else if (Int32.TryParse(rawEnd, out end))
362 {
363 return true;
364 }
365 }
366 }
367
368 start = end = 0;
369 return false;
251 } 370 }
252 private bool TryParseRange(string header, out int start, out int end) 371 private bool TryParseRange(string header, out int start, out int end)
253 { 372 {