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.cs223
1 files changed, 111 insertions, 112 deletions
diff --git a/OpenSim/Capabilities/Handlers/GetTexture/GetTextureHandler.cs b/OpenSim/Capabilities/Handlers/GetTexture/GetTextureHandler.cs
index b497fde..aa6203b 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 public override byte[] Handle(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,84 +145,69 @@ 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 m_assetService.Store(newTexture);
181 return true; 178 WriteTextureData(request, response, newTexture, format);
182 } 179 return true;
183 else
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 m_assetService.Store(newTexture);
193 WriteTextureData(httpRequest, httpResponse, newTexture, format);
194 return true;
195 }
196 } 180 }
197 } 181 }
198 else // it was on the cache 182 }
199 { 183 else // it was on the cache
200// m_log.DebugFormat("[GETTEXTURE]: texture was in the cache"); 184 {
201 WriteTextureData(httpRequest, httpResponse, texture, format); 185 //m_log.DebugFormat("[GETTEXTURE]: texture was in the cache");
202 return true; 186 WriteTextureData(request, response, texture, format);
203 } 187 return true;
204 } 188 }
205 189
190 //response = new Hashtable();
191
192
193 //WriteTextureData(request,response,null,format);
206 // not found 194 // not found
207// m_log.Warn("[GETTEXTURE]: Texture " + textureID + " not found"); 195 //m_log.Warn("[GETTEXTURE]: Texture " + textureID + " not found");
208 httpResponse.StatusCode = (int)System.Net.HttpStatusCode.NotFound; 196 return false;
209 return true;
210 } 197 }
211 198
212 private void WriteTextureData(IOSHttpRequest request, IOSHttpResponse response, AssetBase texture, string format) 199 private void WriteTextureData(Hashtable request, Hashtable response, AssetBase texture, string format)
213 { 200 {
214 string range = request.Headers.GetOne("Range"); 201 Hashtable headers = new Hashtable();
202 response["headers"] = headers;
203
204 string range = String.Empty;
205
206 if (((Hashtable)request["headers"])["range"] != null)
207 range = (string)((Hashtable)request["headers"])["range"];
208
209 else if (((Hashtable)request["headers"])["Range"] != null)
210 range = (string)((Hashtable)request["headers"])["Range"];
215 211
216 if (!String.IsNullOrEmpty(range)) // JP2's only 212 if (!String.IsNullOrEmpty(range)) // JP2's only
217 { 213 {
@@ -239,10 +235,8 @@ namespace OpenSim.Capabilities.Handlers
239 // However, if we return PartialContent (or OK) instead, the viewer will display that resolution. 235 // However, if we return PartialContent (or OK) instead, the viewer will display that resolution.
240 236
241// response.StatusCode = (int)System.Net.HttpStatusCode.RequestedRangeNotSatisfiable; 237// response.StatusCode = (int)System.Net.HttpStatusCode.RequestedRangeNotSatisfiable;
242// response.AddHeader("Content-Range", String.Format("bytes */{0}", texture.Data.Length)); 238 // viewers don't seem to handle RequestedRangeNotSatisfiable and keep retrying with same parameters
243// response.StatusCode = (int)System.Net.HttpStatusCode.OK; 239 response["int_response_code"] = (int)System.Net.HttpStatusCode.NotFound;
244 response.StatusCode = (int)System.Net.HttpStatusCode.PartialContent;
245 response.ContentType = texture.Metadata.ContentType;
246 } 240 }
247 else 241 else
248 { 242 {
@@ -257,41 +251,46 @@ namespace OpenSim.Capabilities.Handlers
257 251
258// m_log.Debug("Serving " + start + " to " + end + " of " + texture.Data.Length + " bytes for texture " + texture.ID); 252// m_log.Debug("Serving " + start + " to " + end + " of " + texture.Data.Length + " bytes for texture " + texture.ID);
259 253
260 // Always return PartialContent, even if the range covered the entire data length 254 response["content-type"] = texture.Metadata.ContentType;
261 // We were accidentally sending back 404 before in this situation 255
262 // https://issues.apache.org/bugzilla/show_bug.cgi?id=51878 supports sending 206 even if the 256 if (start == 0 && len == texture.Data.Length) // well redudante maybe
263 // entire range is requested, and viewer 3.2.2 (and very probably earlier) seems fine with this. 257 {
264 // 258 response["int_response_code"] = (int)System.Net.HttpStatusCode.OK;
265 // We also do not want to send back OK even if the whole range was satisfiable since this causes 259 response["bin_response_data"] = texture.Data;
266 // HTTP textures on at least Imprudence 1.4.0-beta2 to never display the final texture quality. 260 response["int_bytes"] = texture.Data.Length;
267// if (end > maxEnd) 261 }
268// response.StatusCode = (int)System.Net.HttpStatusCode.OK; 262 else
269// else 263 {
270 response.StatusCode = (int)System.Net.HttpStatusCode.PartialContent; 264 response["int_response_code"] = (int)System.Net.HttpStatusCode.PartialContent;
271 265 headers["Content-Range"] = String.Format("bytes {0}-{1}/{2}", start, end, texture.Data.Length);
272 response.ContentLength = len; 266
273 response.ContentType = texture.Metadata.ContentType; 267 byte[] d = new byte[len];
274 response.AddHeader("Content-Range", String.Format("bytes {0}-{1}/{2}", start, end, texture.Data.Length)); 268 Array.Copy(texture.Data, start, d, 0, len);
275 269 response["bin_response_data"] = d;
276 response.Body.Write(texture.Data, start, len); 270 response["int_bytes"] = len;
271 }
272// response.Body.Write(texture.Data, start, len);
277 } 273 }
278 } 274 }
279 else 275 else
280 { 276 {
281 m_log.Warn("[GETTEXTURE]: Malformed Range header: " + range); 277 m_log.Warn("[GETTEXTURE]: Malformed Range header: " + range);
282 response.StatusCode = (int)System.Net.HttpStatusCode.BadRequest; 278 response["int_response_code"] = (int)System.Net.HttpStatusCode.BadRequest;
283 } 279 }
284 } 280 }
285 else // JP2's or other formats 281 else // JP2's or other formats
286 { 282 {
287 // Full content request 283 // Full content request
288 response.StatusCode = (int)System.Net.HttpStatusCode.OK; 284 response["int_response_code"] = (int)System.Net.HttpStatusCode.OK;
289 response.ContentLength = texture.Data.Length;
290 if (format == DefaultFormat) 285 if (format == DefaultFormat)
291 response.ContentType = texture.Metadata.ContentType; 286 response["content_type"] = texture.Metadata.ContentType;
292 else 287 else
293 response.ContentType = "image/" + format; 288 response["content_type"] = "image/" + format;
294 response.Body.Write(texture.Data, 0, texture.Data.Length); 289
290 response["bin_response_data"] = texture.Data;
291 response["int_bytes"] = texture.Data.Length;
292
293// response.Body.Write(texture.Data, 0, texture.Data.Length);
295 } 294 }
296 295
297// if (response.StatusCode < 200 || response.StatusCode > 299) 296// if (response.StatusCode < 200 || response.StatusCode > 299)
@@ -423,4 +422,4 @@ namespace OpenSim.Capabilities.Handlers
423 return null; 422 return null;
424 } 423 }
425 } 424 }
426} \ No newline at end of file 425}