aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Capabilities/Handlers/GetTexture/GetTextureHandler.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Capabilities/Handlers/GetTexture/GetTextureHandler.cs')
-rw-r--r--OpenSim/Capabilities/Handlers/GetTexture/GetTextureHandler.cs225
1 files changed, 112 insertions, 113 deletions
diff --git a/OpenSim/Capabilities/Handlers/GetTexture/GetTextureHandler.cs b/OpenSim/Capabilities/Handlers/GetTexture/GetTextureHandler.cs
index 7b3124a..f3efb53 100644
--- a/OpenSim/Capabilities/Handlers/GetTexture/GetTextureHandler.cs
+++ b/OpenSim/Capabilities/Handlers/GetTexture/GetTextureHandler.cs
@@ -47,36 +47,36 @@ using Caps = OpenSim.Framework.Capabilities.Caps;
47 47
48namespace OpenSim.Capabilities.Handlers 48namespace OpenSim.Capabilities.Handlers
49{ 49{
50 public class GetTextureHandler : BaseStreamHandler 50 public class GetTextureHandler
51 { 51 {
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
54 private IAssetService m_assetService; 55 private IAssetService m_assetService;
55 56
56 public const string DefaultFormat = "x-j2c"; 57 public const string DefaultFormat = "x-j2c";
57 58
58 // TODO: Change this to a config option 59 public GetTextureHandler(IAssetService assService)
59 const string REDIRECT_URL = null;
60
61 public GetTextureHandler(string path, IAssetService assService, string name, string description)
62 : base("GET", path, name, description)
63 { 60 {
64 m_assetService = assService; 61 m_assetService = assService;
65 } 62 }
66 63
67 protected override byte[] ProcessRequest(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) 64 public Hashtable Handle(Hashtable request)
68 { 65 {
69 // Try to parse the texture ID from the request URL 66 Hashtable ret = new Hashtable();
70 NameValueCollection query = HttpUtility.ParseQueryString(httpRequest.Url.Query); 67 ret["int_response_code"] = (int)System.Net.HttpStatusCode.NotFound;
71 string textureStr = query.GetOne("texture_id"); 68 ret["content_type"] = "text/plain";
72 string format = query.GetOne("format"); 69 ret["keepalive"] = false;
70 ret["reusecontext"] = false;
71 ret["int_bytes"] = 0;
72 string textureStr = (string)request["texture_id"];
73 string format = (string)request["format"];
73 74
74 //m_log.DebugFormat("[GETTEXTURE]: called {0}", textureStr); 75 //m_log.DebugFormat("[GETTEXTURE]: called {0}", textureStr);
75 76
76 if (m_assetService == null) 77 if (m_assetService == null)
77 { 78 {
78 m_log.Error("[GETTEXTURE]: Cannot fetch texture " + textureStr + " without an asset service"); 79 m_log.Error("[GETTEXTURE]: Cannot fetch texture " + textureStr + " without an asset service");
79 httpResponse.StatusCode = (int)System.Net.HttpStatusCode.NotFound;
80 } 80 }
81 81
82 UUID textureID; 82 UUID textureID;
@@ -91,30 +91,41 @@ namespace OpenSim.Capabilities.Handlers
91 } 91 }
92 else 92 else
93 { 93 {
94 formats = WebUtil.GetPreferredImageTypes(httpRequest.Headers.Get("Accept")); 94 formats = new string[1] { DefaultFormat }; // default
95 if (((Hashtable)request["headers"])["Accept"] != null)
96 formats = WebUtil.GetPreferredImageTypes((string)((Hashtable)request["headers"])["Accept"]);
95 if (formats.Length == 0) 97 if (formats.Length == 0)
96 formats = new string[1] { DefaultFormat }; // default 98 formats = new string[1] { DefaultFormat }; // default
97 99
98 } 100 }
99 // OK, we have an array with preferred formats, possibly with only one entry 101 // OK, we have an array with preferred formats, possibly with only one entry
100 102 bool foundtexture = false;
101 httpResponse.StatusCode = (int)System.Net.HttpStatusCode.NotFound;
102 foreach (string f in formats) 103 foreach (string f in formats)
103 { 104 {
104 if (FetchTexture(httpRequest, httpResponse, textureID, f)) 105 foundtexture = FetchTexture(request, ret, textureID, f);
106 if (foundtexture)
105 break; 107 break;
106 } 108 }
109 if (!foundtexture)
110 {
111 ret["int_response_code"] = 404;
112 ret["error_status_text"] = "not found";
113 ret["str_response_string"] = "not found";
114 ret["content_type"] = "text/plain";
115 ret["keepalive"] = false;
116 ret["reusecontext"] = false;
117 ret["int_bytes"] = 0;
118 }
107 } 119 }
108 else 120 else
109 { 121 {
110 m_log.Warn("[GETTEXTURE]: Failed to parse a texture_id from GetTexture request: " + httpRequest.Url); 122 m_log.Warn("[GETTEXTURE]: Failed to parse a texture_id from GetTexture request: " + (string)request["uri"]);
111 } 123 }
112 124
113// m_log.DebugFormat( 125// m_log.DebugFormat(
114// "[GETTEXTURE]: For texture {0} sending back response {1}, data length {2}", 126// "[GETTEXTURE]: For texture {0} sending back response {1}, data length {2}",
115// textureID, httpResponse.StatusCode, httpResponse.ContentLength); 127// textureID, httpResponse.StatusCode, httpResponse.ContentLength);
116 128 return ret;
117 return null;
118 } 129 }
119 130
120 /// <summary> 131 /// <summary>
@@ -125,7 +136,7 @@ namespace OpenSim.Capabilities.Handlers
125 /// <param name="textureID"></param> 136 /// <param name="textureID"></param>
126 /// <param name="format"></param> 137 /// <param name="format"></param>
127 /// <returns>False for "caller try another codec"; true otherwise</returns> 138 /// <returns>False for "caller try another codec"; true otherwise</returns>
128 private bool FetchTexture(IOSHttpRequest httpRequest, IOSHttpResponse httpResponse, UUID textureID, string format) 139 private bool FetchTexture(Hashtable request, Hashtable response, UUID textureID, string format)
129 { 140 {
130// m_log.DebugFormat("[GETTEXTURE]: {0} with requested format {1}", textureID, format); 141// m_log.DebugFormat("[GETTEXTURE]: {0} with requested format {1}", textureID, format);
131 AssetBase texture; 142 AssetBase texture;
@@ -134,85 +145,70 @@ namespace OpenSim.Capabilities.Handlers
134 if (format != DefaultFormat) 145 if (format != DefaultFormat)
135 fullID = fullID + "-" + format; 146 fullID = fullID + "-" + format;
136 147
137 if (!String.IsNullOrEmpty(REDIRECT_URL)) 148 // try the cache
149 texture = m_assetService.GetCached(fullID);
150
151 if (texture == null)
138 { 152 {
139 // Only try to fetch locally cached textures. Misses are redirected 153 //m_log.DebugFormat("[GETTEXTURE]: texture was not in the cache");
140 texture = m_assetService.GetCached(fullID); 154
155 // Fetch locally or remotely. Misses return a 404
156 texture = m_assetService.Get(textureID.ToString());
141 157
142 if (texture != null) 158 if (texture != null)
143 { 159 {
144 if (texture.Type != (sbyte)AssetType.Texture) 160 if (texture.Type != (sbyte)AssetType.Texture)
161 return true;
162
163 if (format == DefaultFormat)
145 { 164 {
146 httpResponse.StatusCode = (int)System.Net.HttpStatusCode.NotFound; 165 WriteTextureData(request, response, texture, format);
147 return true; 166 return true;
148 } 167 }
149 WriteTextureData(httpRequest, httpResponse, texture, format); 168 else
150 }
151 else
152 {
153 string textureUrl = REDIRECT_URL + textureID.ToString();
154 m_log.Debug("[GETTEXTURE]: Redirecting texture request to " + textureUrl);
155 httpResponse.RedirectLocation = textureUrl;
156 return true;
157 }
158 }
159 else // no redirect
160 {
161 // try the cache
162 texture = m_assetService.GetCached(fullID);
163
164 if (texture == null)
165 {
166// m_log.DebugFormat("[GETTEXTURE]: texture was not in the cache");
167
168 // Fetch locally or remotely. Misses return a 404
169 texture = m_assetService.Get(textureID.ToString());
170
171 if (texture != null)
172 { 169 {
173 if (texture.Type != (sbyte)AssetType.Texture) 170 AssetBase newTexture = new AssetBase(texture.ID + "-" + format, texture.Name, (sbyte)AssetType.Texture, texture.Metadata.CreatorID);
174 { 171 newTexture.Data = ConvertTextureData(texture, format);
175 httpResponse.StatusCode = (int)System.Net.HttpStatusCode.NotFound; 172 if (newTexture.Data.Length == 0)
176 return true; 173 return false; // !!! Caller try another codec, please!
177 } 174
178 if (format == DefaultFormat) 175 newTexture.Flags = AssetFlags.Collectable;
179 { 176 newTexture.Temporary = true;
180 WriteTextureData(httpRequest, httpResponse, texture, format); 177 newTexture.Local = true;
181 return true; 178 m_assetService.Store(newTexture);
182 } 179 WriteTextureData(request, response, newTexture, format);
183 else 180 return true;
184 {
185 AssetBase newTexture = new AssetBase(texture.ID + "-" + format, texture.Name, (sbyte)AssetType.Texture, texture.Metadata.CreatorID);
186 newTexture.Data = ConvertTextureData(texture, format);
187 if (newTexture.Data.Length == 0)
188 return false; // !!! Caller try another codec, please!
189
190 newTexture.Flags = AssetFlags.Collectable;
191 newTexture.Temporary = true;
192 newTexture.Local = true;
193 m_assetService.Store(newTexture);
194 WriteTextureData(httpRequest, httpResponse, newTexture, format);
195 return true;
196 }
197 } 181 }
198 } 182 }
199 else // it was on the cache 183 }
200 { 184 else // it was on the cache
201// m_log.DebugFormat("[GETTEXTURE]: texture was in the cache"); 185 {
202 WriteTextureData(httpRequest, httpResponse, texture, format); 186 //m_log.DebugFormat("[GETTEXTURE]: texture was in the cache");
203 return true; 187 WriteTextureData(request, response, texture, format);
204 } 188 return true;
205 } 189 }
206 190
191 //response = new Hashtable();
192
193
194 //WriteTextureData(request,response,null,format);
207 // not found 195 // not found
208// m_log.Warn("[GETTEXTURE]: Texture " + textureID + " not found"); 196 //m_log.Warn("[GETTEXTURE]: Texture " + textureID + " not found");
209 httpResponse.StatusCode = (int)System.Net.HttpStatusCode.NotFound; 197 return false;
210 return true;
211 } 198 }
212 199
213 private void WriteTextureData(IOSHttpRequest request, IOSHttpResponse response, AssetBase texture, string format) 200 private void WriteTextureData(Hashtable request, Hashtable response, AssetBase texture, string format)
214 { 201 {
215 string range = request.Headers.GetOne("Range"); 202 Hashtable headers = new Hashtable();
203 response["headers"] = headers;
204
205 string range = String.Empty;
206
207 if (((Hashtable)request["headers"])["range"] != null)
208 range = (string)((Hashtable)request["headers"])["range"];
209
210 else if (((Hashtable)request["headers"])["Range"] != null)
211 range = (string)((Hashtable)request["headers"])["Range"];
216 212
217 if (!String.IsNullOrEmpty(range)) // JP2's only 213 if (!String.IsNullOrEmpty(range)) // JP2's only
218 { 214 {
@@ -240,10 +236,8 @@ namespace OpenSim.Capabilities.Handlers
240 // However, if we return PartialContent (or OK) instead, the viewer will display that resolution. 236 // However, if we return PartialContent (or OK) instead, the viewer will display that resolution.
241 237
242// response.StatusCode = (int)System.Net.HttpStatusCode.RequestedRangeNotSatisfiable; 238// response.StatusCode = (int)System.Net.HttpStatusCode.RequestedRangeNotSatisfiable;
243// response.AddHeader("Content-Range", String.Format("bytes */{0}", texture.Data.Length)); 239 // viewers don't seem to handle RequestedRangeNotSatisfiable and keep retrying with same parameters
244// response.StatusCode = (int)System.Net.HttpStatusCode.OK; 240 response["int_response_code"] = (int)System.Net.HttpStatusCode.NotFound;
245 response.StatusCode = (int)System.Net.HttpStatusCode.PartialContent;
246 response.ContentType = texture.Metadata.ContentType;
247 } 241 }
248 else 242 else
249 { 243 {
@@ -258,41 +252,46 @@ namespace OpenSim.Capabilities.Handlers
258 252
259// m_log.Debug("Serving " + start + " to " + end + " of " + texture.Data.Length + " bytes for texture " + texture.ID); 253// m_log.Debug("Serving " + start + " to " + end + " of " + texture.Data.Length + " bytes for texture " + texture.ID);
260 254
261 // Always return PartialContent, even if the range covered the entire data length 255 response["content-type"] = texture.Metadata.ContentType;
262 // We were accidentally sending back 404 before in this situation 256
263 // https://issues.apache.org/bugzilla/show_bug.cgi?id=51878 supports sending 206 even if the 257 if (start == 0 && len == texture.Data.Length) // well redudante maybe
264 // entire range is requested, and viewer 3.2.2 (and very probably earlier) seems fine with this. 258 {
265 // 259 response["int_response_code"] = (int)System.Net.HttpStatusCode.OK;
266 // We also do not want to send back OK even if the whole range was satisfiable since this causes 260 response["bin_response_data"] = texture.Data;
267 // HTTP textures on at least Imprudence 1.4.0-beta2 to never display the final texture quality. 261 response["int_bytes"] = texture.Data.Length;
268// if (end > maxEnd) 262 }
269// response.StatusCode = (int)System.Net.HttpStatusCode.OK; 263 else
270// else 264 {
271 response.StatusCode = (int)System.Net.HttpStatusCode.PartialContent; 265 response["int_response_code"] = (int)System.Net.HttpStatusCode.PartialContent;
272 266 headers["Content-Range"] = String.Format("bytes {0}-{1}/{2}", start, end, texture.Data.Length);
273 response.ContentLength = len; 267
274 response.ContentType = texture.Metadata.ContentType; 268 byte[] d = new byte[len];
275 response.AddHeader("Content-Range", String.Format("bytes {0}-{1}/{2}", start, end, texture.Data.Length)); 269 Array.Copy(texture.Data, start, d, 0, len);
276 270 response["bin_response_data"] = d;
277 response.Body.Write(texture.Data, start, len); 271 response["int_bytes"] = len;
272 }
273// response.Body.Write(texture.Data, start, len);
278 } 274 }
279 } 275 }
280 else 276 else
281 { 277 {
282 m_log.Warn("[GETTEXTURE]: Malformed Range header: " + range); 278 m_log.Warn("[GETTEXTURE]: Malformed Range header: " + range);
283 response.StatusCode = (int)System.Net.HttpStatusCode.BadRequest; 279 response["int_response_code"] = (int)System.Net.HttpStatusCode.BadRequest;
284 } 280 }
285 } 281 }
286 else // JP2's or other formats 282 else // JP2's or other formats
287 { 283 {
288 // Full content request 284 // Full content request
289 response.StatusCode = (int)System.Net.HttpStatusCode.OK; 285 response["int_response_code"] = (int)System.Net.HttpStatusCode.OK;
290 response.ContentLength = texture.Data.Length;
291 if (format == DefaultFormat) 286 if (format == DefaultFormat)
292 response.ContentType = texture.Metadata.ContentType; 287 response["content_type"] = texture.Metadata.ContentType;
293 else 288 else
294 response.ContentType = "image/" + format; 289 response["content_type"] = "image/" + format;
295 response.Body.Write(texture.Data, 0, texture.Data.Length); 290
291 response["bin_response_data"] = texture.Data;
292 response["int_bytes"] = texture.Data.Length;
293
294// response.Body.Write(texture.Data, 0, texture.Data.Length);
296 } 295 }
297 296
298// if (response.StatusCode < 200 || response.StatusCode > 299) 297// if (response.StatusCode < 200 || response.StatusCode > 299)
@@ -424,4 +423,4 @@ namespace OpenSim.Capabilities.Handlers
424 return null; 423 return null;
425 } 424 }
426 } 425 }
427} \ No newline at end of file 426}