aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Capabilities/Handlers/GetTexture/GetTextureRobustHandler.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Capabilities/Handlers/GetTexture/GetTextureRobustHandler.cs')
-rw-r--r--OpenSim/Capabilities/Handlers/GetTexture/GetTextureRobustHandler.cs96
1 files changed, 48 insertions, 48 deletions
diff --git a/OpenSim/Capabilities/Handlers/GetTexture/GetTextureRobustHandler.cs b/OpenSim/Capabilities/Handlers/GetTexture/GetTextureRobustHandler.cs
index 5f86ed4..d5df7a2 100644
--- a/OpenSim/Capabilities/Handlers/GetTexture/GetTextureRobustHandler.cs
+++ b/OpenSim/Capabilities/Handlers/GetTexture/GetTextureRobustHandler.cs
@@ -24,7 +24,7 @@
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 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. 25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */ 26 */
27 27
28using System; 28using System;
29using System.Collections; 29using System.Collections;
30using System.Collections.Specialized; 30using System.Collections.Specialized;
@@ -44,7 +44,7 @@ using OpenSim.Framework.Servers.HttpServer;
44using OpenSim.Region.Framework.Interfaces; 44using OpenSim.Region.Framework.Interfaces;
45using OpenSim.Services.Interfaces; 45using OpenSim.Services.Interfaces;
46using Caps = OpenSim.Framework.Capabilities.Caps; 46using Caps = OpenSim.Framework.Capabilities.Caps;
47 47
48namespace OpenSim.Capabilities.Handlers 48namespace OpenSim.Capabilities.Handlers
49{ 49{
50 public class GetTextureRobustHandler : BaseStreamHandler 50 public class GetTextureRobustHandler : BaseStreamHandler
@@ -52,9 +52,9 @@ namespace OpenSim.Capabilities.Handlers
52 private static readonly ILog m_log = 52 private static readonly ILog m_log =
53 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 53 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
54 private IAssetService m_assetService; 54 private IAssetService m_assetService;
55 55
56 public const string DefaultFormat = "x-j2c"; 56 public const string DefaultFormat = "x-j2c";
57 57
58 // TODO: Change this to a config option 58 // TODO: Change this to a config option
59 private string m_RedirectURL = null; 59 private string m_RedirectURL = null;
60 60
@@ -66,28 +66,28 @@ namespace OpenSim.Capabilities.Handlers
66 if (m_RedirectURL != null && !m_RedirectURL.EndsWith("/")) 66 if (m_RedirectURL != null && !m_RedirectURL.EndsWith("/"))
67 m_RedirectURL += "/"; 67 m_RedirectURL += "/";
68 } 68 }
69 69
70 protected override byte[] ProcessRequest(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) 70 protected override byte[] ProcessRequest(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
71 { 71 {
72 // Try to parse the texture ID from the request URL 72 // Try to parse the texture ID from the request URL
73 NameValueCollection query = HttpUtility.ParseQueryString(httpRequest.Url.Query); 73 NameValueCollection query = HttpUtility.ParseQueryString(httpRequest.Url.Query);
74 string textureStr = query.GetOne("texture_id"); 74 string textureStr = query.GetOne("texture_id");
75 string format = query.GetOne("format"); 75 string format = query.GetOne("format");
76 76
77 //m_log.DebugFormat("[GETTEXTURE]: called {0}", textureStr); 77 //m_log.DebugFormat("[GETTEXTURE]: called {0}", textureStr);
78 78
79 if (m_assetService == null) 79 if (m_assetService == null)
80 { 80 {
81 m_log.Error("[GETTEXTURE]: Cannot fetch texture " + textureStr + " without an asset service"); 81 m_log.Error("[GETTEXTURE]: Cannot fetch texture " + textureStr + " without an asset service");
82 httpResponse.StatusCode = (int)System.Net.HttpStatusCode.NotFound; 82 httpResponse.StatusCode = (int)System.Net.HttpStatusCode.NotFound;
83 return null; 83 return null;
84 } 84 }
85 85
86 UUID textureID; 86 UUID textureID;
87 if (!String.IsNullOrEmpty(textureStr) && UUID.TryParse(textureStr, out textureID)) 87 if (!String.IsNullOrEmpty(textureStr) && UUID.TryParse(textureStr, out textureID))
88 { 88 {
89// m_log.DebugFormat("[GETTEXTURE]: Received request for texture id {0}", textureID); 89// m_log.DebugFormat("[GETTEXTURE]: Received request for texture id {0}", textureID);
90 90
91 string[] formats; 91 string[] formats;
92 if (!string.IsNullOrEmpty(format)) 92 if (!string.IsNullOrEmpty(format))
93 { 93 {
@@ -98,10 +98,10 @@ namespace OpenSim.Capabilities.Handlers
98 formats = WebUtil.GetPreferredImageTypes(httpRequest.Headers.Get("Accept")); 98 formats = WebUtil.GetPreferredImageTypes(httpRequest.Headers.Get("Accept"));
99 if (formats.Length == 0) 99 if (formats.Length == 0)
100 formats = new string[1] { DefaultFormat }; // default 100 formats = new string[1] { DefaultFormat }; // default
101 101
102 } 102 }
103 // OK, we have an array with preferred formats, possibly with only one entry 103 // OK, we have an array with preferred formats, possibly with only one entry
104 104
105 httpResponse.StatusCode = (int)System.Net.HttpStatusCode.NotFound; 105 httpResponse.StatusCode = (int)System.Net.HttpStatusCode.NotFound;
106 foreach (string f in formats) 106 foreach (string f in formats)
107 { 107 {
@@ -113,14 +113,14 @@ namespace OpenSim.Capabilities.Handlers
113 { 113 {
114 m_log.Warn("[GETTEXTURE]: Failed to parse a texture_id from GetTexture request: " + httpRequest.Url); 114 m_log.Warn("[GETTEXTURE]: Failed to parse a texture_id from GetTexture request: " + httpRequest.Url);
115 } 115 }
116 116
117// m_log.DebugFormat( 117// m_log.DebugFormat(
118// "[GETTEXTURE]: For texture {0} sending back response {1}, data length {2}", 118// "[GETTEXTURE]: For texture {0} sending back response {1}, data length {2}",
119// textureID, httpResponse.StatusCode, httpResponse.ContentLength); 119// textureID, httpResponse.StatusCode, httpResponse.ContentLength);
120 120
121 return null; 121 return null;
122 } 122 }
123 123
124 /// <summary> 124 /// <summary>
125 /// 125 ///
126 /// </summary> 126 /// </summary>
@@ -133,16 +133,16 @@ namespace OpenSim.Capabilities.Handlers
133 { 133 {
134// m_log.DebugFormat("[GETTEXTURE]: {0} with requested format {1}", textureID, format); 134// m_log.DebugFormat("[GETTEXTURE]: {0} with requested format {1}", textureID, format);
135 AssetBase texture; 135 AssetBase texture;
136 136
137 string fullID = textureID.ToString(); 137 string fullID = textureID.ToString();
138 if (format != DefaultFormat) 138 if (format != DefaultFormat)
139 fullID = fullID + "-" + format; 139 fullID = fullID + "-" + format;
140 140
141 if (!String.IsNullOrEmpty(m_RedirectURL)) 141 if (!String.IsNullOrEmpty(m_RedirectURL))
142 { 142 {
143 // Only try to fetch locally cached textures. Misses are redirected 143 // Only try to fetch locally cached textures. Misses are redirected
144 texture = m_assetService.GetCached(fullID); 144 texture = m_assetService.GetCached(fullID);
145 145
146 if (texture != null) 146 if (texture != null)
147 { 147 {
148 if (texture.Type != (sbyte)AssetType.Texture) 148 if (texture.Type != (sbyte)AssetType.Texture)
@@ -166,14 +166,14 @@ namespace OpenSim.Capabilities.Handlers
166 { 166 {
167 // try the cache 167 // try the cache
168 texture = m_assetService.GetCached(fullID); 168 texture = m_assetService.GetCached(fullID);
169 169
170 if (texture == null) 170 if (texture == null)
171 { 171 {
172// m_log.DebugFormat("[GETTEXTURE]: texture was not in the cache"); 172// m_log.DebugFormat("[GETTEXTURE]: texture was not in the cache");
173 173
174 // Fetch locally or remotely. Misses return a 404 174 // Fetch locally or remotely. Misses return a 404
175 texture = m_assetService.Get(textureID.ToString()); 175 texture = m_assetService.Get(textureID.ToString());
176 176
177 if (texture != null) 177 if (texture != null)
178 { 178 {
179 if (texture.Type != (sbyte)AssetType.Texture) 179 if (texture.Type != (sbyte)AssetType.Texture)
@@ -192,7 +192,7 @@ namespace OpenSim.Capabilities.Handlers
192 newTexture.Data = ConvertTextureData(texture, format); 192 newTexture.Data = ConvertTextureData(texture, format);
193 if (newTexture.Data.Length == 0) 193 if (newTexture.Data.Length == 0)
194 return false; // !!! Caller try another codec, please! 194 return false; // !!! Caller try another codec, please!
195 195
196 newTexture.Flags = AssetFlags.Collectable; 196 newTexture.Flags = AssetFlags.Collectable;
197 newTexture.Temporary = true; 197 newTexture.Temporary = true;
198 newTexture.Local = true; 198 newTexture.Local = true;
@@ -209,17 +209,17 @@ namespace OpenSim.Capabilities.Handlers
209 return true; 209 return true;
210 } 210 }
211 } 211 }
212 212
213 // not found 213 // not found
214// m_log.Warn("[GETTEXTURE]: Texture " + textureID + " not found"); 214// m_log.Warn("[GETTEXTURE]: Texture " + textureID + " not found");
215 httpResponse.StatusCode = (int)System.Net.HttpStatusCode.NotFound; 215 httpResponse.StatusCode = (int)System.Net.HttpStatusCode.NotFound;
216 return true; 216 return true;
217 } 217 }
218 218
219 private void WriteTextureData(IOSHttpRequest request, IOSHttpResponse response, AssetBase texture, string format) 219 private void WriteTextureData(IOSHttpRequest request, IOSHttpResponse response, AssetBase texture, string format)
220 { 220 {
221 string range = request.Headers.GetOne("Range"); 221 string range = request.Headers.GetOne("Range");
222 222
223 if (!String.IsNullOrEmpty(range)) // JP2's only 223 if (!String.IsNullOrEmpty(range)) // JP2's only
224 { 224 {
225 // Range request 225 // Range request
@@ -233,7 +233,7 @@ namespace OpenSim.Capabilities.Handlers
233// m_log.DebugFormat( 233// m_log.DebugFormat(
234// "[GETTEXTURE]: Client requested range for texture {0} starting at {1} but texture has end of {2}", 234// "[GETTEXTURE]: Client requested range for texture {0} starting at {1} but texture has end of {2}",
235// texture.ID, start, texture.Data.Length); 235// texture.ID, start, texture.Data.Length);
236 236
237 // Stricly speaking, as per http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html, we should be sending back 237 // Stricly speaking, as per http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html, we should be sending back
238 // Requested Range Not Satisfiable (416) here. However, it appears that at least recent implementations 238 // Requested Range Not Satisfiable (416) here. However, it appears that at least recent implementations
239 // of the Linden Lab viewer (3.2.1 and 3.3.4 and probably earlier), a viewer that has previously 239 // of the Linden Lab viewer (3.2.1 and 3.3.4 and probably earlier), a viewer that has previously
@@ -244,7 +244,7 @@ namespace OpenSim.Capabilities.Handlers
244 // level 2. If this estimate is greater than the total texture size, returning a RequestedRangeNotSatisfiable 244 // level 2. If this estimate is greater than the total texture size, returning a RequestedRangeNotSatisfiable
245 // here will cause the viewer to treat the texture as bad and never display the full resolution 245 // here will cause the viewer to treat the texture as bad and never display the full resolution
246 // However, if we return PartialContent (or OK) instead, the viewer will display that resolution. 246 // However, if we return PartialContent (or OK) instead, the viewer will display that resolution.
247 247
248// response.StatusCode = (int)System.Net.HttpStatusCode.RequestedRangeNotSatisfiable; 248// response.StatusCode = (int)System.Net.HttpStatusCode.RequestedRangeNotSatisfiable;
249// response.AddHeader("Content-Range", String.Format("bytes */{0}", texture.Data.Length)); 249// response.AddHeader("Content-Range", String.Format("bytes */{0}", texture.Data.Length));
250// response.StatusCode = (int)System.Net.HttpStatusCode.OK; 250// response.StatusCode = (int)System.Net.HttpStatusCode.OK;
@@ -257,13 +257,13 @@ namespace OpenSim.Capabilities.Handlers
257 // the rest of the entity. 257 // the rest of the entity.
258 if (end == -1) 258 if (end == -1)
259 end = int.MaxValue; 259 end = int.MaxValue;
260 260
261 end = Utils.Clamp(end, 0, texture.Data.Length - 1); 261 end = Utils.Clamp(end, 0, texture.Data.Length - 1);
262 start = Utils.Clamp(start, 0, end); 262 start = Utils.Clamp(start, 0, end);
263 int len = end - start + 1; 263 int len = end - start + 1;
264 264
265// m_log.Debug("Serving " + start + " to " + end + " of " + texture.Data.Length + " bytes for texture " + texture.ID); 265// m_log.Debug("Serving " + start + " to " + end + " of " + texture.Data.Length + " bytes for texture " + texture.ID);
266 266
267 // Always return PartialContent, even if the range covered the entire data length 267 // Always return PartialContent, even if the range covered the entire data length
268 // We were accidentally sending back 404 before in this situation 268 // We were accidentally sending back 404 before in this situation
269 // https://issues.apache.org/bugzilla/show_bug.cgi?id=51878 supports sending 206 even if the 269 // https://issues.apache.org/bugzilla/show_bug.cgi?id=51878 supports sending 206 even if the
@@ -275,11 +275,11 @@ namespace OpenSim.Capabilities.Handlers
275// response.StatusCode = (int)System.Net.HttpStatusCode.OK; 275// response.StatusCode = (int)System.Net.HttpStatusCode.OK;
276// else 276// else
277 response.StatusCode = (int)System.Net.HttpStatusCode.PartialContent; 277 response.StatusCode = (int)System.Net.HttpStatusCode.PartialContent;
278 278
279 response.ContentLength = len; 279 response.ContentLength = len;
280 response.ContentType = texture.Metadata.ContentType; 280 response.ContentType = texture.Metadata.ContentType;
281 response.AddHeader("Content-Range", String.Format("bytes {0}-{1}/{2}", start, end, texture.Data.Length)); 281 response.AddHeader("Content-Range", String.Format("bytes {0}-{1}/{2}", start, end, texture.Data.Length));
282 282
283 response.Body.Write(texture.Data, start, len); 283 response.Body.Write(texture.Data, start, len);
284 } 284 }
285 } 285 }
@@ -300,7 +300,7 @@ namespace OpenSim.Capabilities.Handlers
300 response.ContentType = "image/" + format; 300 response.ContentType = "image/" + format;
301 response.Body.Write(texture.Data, 0, texture.Data.Length); 301 response.Body.Write(texture.Data, 0, texture.Data.Length);
302 } 302 }
303 303
304// if (response.StatusCode < 200 || response.StatusCode > 299) 304// if (response.StatusCode < 200 || response.StatusCode > 299)
305// m_log.WarnFormat( 305// m_log.WarnFormat(
306// "[GETTEXTURE]: For texture {0} requested range {1} responded {2} with content length {3} (actual {4})", 306// "[GETTEXTURE]: For texture {0} requested range {1} responded {2} with content length {3} (actual {4})",
@@ -310,7 +310,7 @@ namespace OpenSim.Capabilities.Handlers
310// "[GETTEXTURE]: For texture {0} requested range {1} responded {2} with content length {3} (actual {4})", 310// "[GETTEXTURE]: For texture {0} requested range {1} responded {2} with content length {3} (actual {4})",
311// texture.FullID, range, response.StatusCode, response.ContentLength, texture.Data.Length); 311// texture.FullID, range, response.StatusCode, response.ContentLength, texture.Data.Length);
312 } 312 }
313 313
314 /// <summary> 314 /// <summary>
315 /// Parse a range header. 315 /// Parse a range header.
316 /// </summary> 316 /// </summary>
@@ -327,18 +327,18 @@ namespace OpenSim.Capabilities.Handlers
327 private bool TryParseRange(string header, out int start, out int end) 327 private bool TryParseRange(string header, out int start, out int end)
328 { 328 {
329 start = end = 0; 329 start = end = 0;
330 330
331 if (header.StartsWith("bytes=")) 331 if (header.StartsWith("bytes="))
332 { 332 {
333 string[] rangeValues = header.Substring(6).Split('-'); 333 string[] rangeValues = header.Substring(6).Split('-');
334 334
335 if (rangeValues.Length == 2) 335 if (rangeValues.Length == 2)
336 { 336 {
337 if (!Int32.TryParse(rangeValues[0], out start)) 337 if (!Int32.TryParse(rangeValues[0], out start))
338 return false; 338 return false;
339 339
340 string rawEnd = rangeValues[1]; 340 string rawEnd = rangeValues[1];
341 341
342 if (rawEnd == "") 342 if (rawEnd == "")
343 { 343 {
344 end = -1; 344 end = -1;
@@ -350,27 +350,27 @@ namespace OpenSim.Capabilities.Handlers
350 } 350 }
351 } 351 }
352 } 352 }
353 353
354 start = end = 0; 354 start = end = 0;
355 return false; 355 return false;
356 } 356 }
357 357
358 private byte[] ConvertTextureData(AssetBase texture, string format) 358 private byte[] ConvertTextureData(AssetBase texture, string format)
359 { 359 {
360 m_log.DebugFormat("[GETTEXTURE]: Converting texture {0} to {1}", texture.ID, format); 360 m_log.DebugFormat("[GETTEXTURE]: Converting texture {0} to {1}", texture.ID, format);
361 byte[] data = new byte[0]; 361 byte[] data = new byte[0];
362 362
363 MemoryStream imgstream = new MemoryStream(); 363 MemoryStream imgstream = new MemoryStream();
364 Bitmap mTexture = null; 364 Bitmap mTexture = null;
365 ManagedImage managedImage = null; 365 ManagedImage managedImage = null;
366 Image image = null; 366 Image image = null;
367 367
368 try 368 try
369 { 369 {
370 // Taking our jpeg2000 data, decoding it, then saving it to a byte array with regular data 370 // Taking our jpeg2000 data, decoding it, then saving it to a byte array with regular data
371 371
372 imgstream = new MemoryStream(); 372 imgstream = new MemoryStream();
373 373
374 // Decode image to System.Drawing.Image 374 // Decode image to System.Drawing.Image
375 if (OpenJPEG.DecodeToImage(texture.Data, out managedImage, out image) && image != null) 375 if (OpenJPEG.DecodeToImage(texture.Data, out managedImage, out image) && image != null)
376 { 376 {
@@ -380,7 +380,7 @@ namespace OpenSim.Capabilities.Handlers
380 using(EncoderParameters myEncoderParameters = new EncoderParameters()) 380 using(EncoderParameters myEncoderParameters = new EncoderParameters())
381 { 381 {
382 myEncoderParameters.Param[0] = new EncoderParameter(Encoder.Quality,95L); 382 myEncoderParameters.Param[0] = new EncoderParameter(Encoder.Quality,95L);
383 383
384 // Save bitmap to stream 384 // Save bitmap to stream
385 ImageCodecInfo codec = GetEncoderInfo("image/" + format); 385 ImageCodecInfo codec = GetEncoderInfo("image/" + format);
386 if (codec != null) 386 if (codec != null)
@@ -404,10 +404,10 @@ namespace OpenSim.Capabilities.Handlers
404 // If we encountered an exception, one or more of these will be null 404 // If we encountered an exception, one or more of these will be null
405 if (mTexture != null) 405 if (mTexture != null)
406 mTexture.Dispose(); 406 mTexture.Dispose();
407 407
408 if (image != null) 408 if (image != null)
409 image.Dispose(); 409 image.Dispose();
410 410
411 if(managedImage != null) 411 if(managedImage != null)
412 managedImage.Clear(); 412 managedImage.Clear();
413 413
@@ -417,10 +417,10 @@ namespace OpenSim.Capabilities.Handlers
417 imgstream.Dispose(); 417 imgstream.Dispose();
418 } 418 }
419 } 419 }
420 420
421 return data; 421 return data;
422 } 422 }
423 423
424 // From msdn 424 // From msdn
425 private static ImageCodecInfo GetEncoderInfo(String mimeType) 425 private static ImageCodecInfo GetEncoderInfo(String mimeType)
426 { 426 {