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.cs200
1 files changed, 92 insertions, 108 deletions
diff --git a/OpenSim/Capabilities/Handlers/GetTexture/GetTextureHandler.cs b/OpenSim/Capabilities/Handlers/GetTexture/GetTextureHandler.cs
index b497fde..822c50d 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,30 @@ 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
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 if (FetchTexture(request, ret, textureID, f))
105 break; 106 break;
106 } 107 }
107 } 108 }
108 else 109 else
109 { 110 {
110 m_log.Warn("[GETTEXTURE]: Failed to parse a texture_id from GetTexture request: " + httpRequest.Url); 111 m_log.Warn("[GETTEXTURE]: Failed to parse a texture_id from GetTexture request: " + (string)request["uri"]);
111 } 112 }
112 113
113// m_log.DebugFormat( 114// m_log.DebugFormat(
114// "[GETTEXTURE]: For texture {0} sending back response {1}, data length {2}", 115// "[GETTEXTURE]: For texture {0} sending back response {1}, data length {2}",
115// textureID, httpResponse.StatusCode, httpResponse.ContentLength); 116// textureID, httpResponse.StatusCode, httpResponse.ContentLength);
116 117 return ret;
117 return null;
118 } 118 }
119 119
120 /// <summary> 120 /// <summary>
@@ -125,7 +125,7 @@ namespace OpenSim.Capabilities.Handlers
125 /// <param name="textureID"></param> 125 /// <param name="textureID"></param>
126 /// <param name="format"></param> 126 /// <param name="format"></param>
127 /// <returns>False for "caller try another codec"; true otherwise</returns> 127 /// <returns>False for "caller try another codec"; true otherwise</returns>
128 private bool FetchTexture(IOSHttpRequest httpRequest, IOSHttpResponse httpResponse, UUID textureID, string format) 128 private bool FetchTexture(Hashtable request, Hashtable response, UUID textureID, string format)
129 { 129 {
130// m_log.DebugFormat("[GETTEXTURE]: {0} with requested format {1}", textureID, format); 130// m_log.DebugFormat("[GETTEXTURE]: {0} with requested format {1}", textureID, format);
131 AssetBase texture; 131 AssetBase texture;
@@ -134,84 +134,65 @@ namespace OpenSim.Capabilities.Handlers
134 if (format != DefaultFormat) 134 if (format != DefaultFormat)
135 fullID = fullID + "-" + format; 135 fullID = fullID + "-" + format;
136 136
137 if (!String.IsNullOrEmpty(REDIRECT_URL)) 137 // try the cache
138 texture = m_assetService.GetCached(fullID);
139
140 if (texture == null)
138 { 141 {
139 // Only try to fetch locally cached textures. Misses are redirected 142 //m_log.DebugFormat("[GETTEXTURE]: texture was not in the cache");
140 texture = m_assetService.GetCached(fullID); 143
144 // Fetch locally or remotely. Misses return a 404
145 texture = m_assetService.Get(textureID.ToString());
141 146
142 if (texture != null) 147 if (texture != null)
143 { 148 {
144 if (texture.Type != (sbyte)AssetType.Texture) 149 if (texture.Type != (sbyte)AssetType.Texture)
150 return true;
151
152 if (format == DefaultFormat)
145 { 153 {
146 httpResponse.StatusCode = (int)System.Net.HttpStatusCode.NotFound; 154 WriteTextureData(request, response, texture, format);
147 return true; 155 return true;
148 } 156 }
149 WriteTextureData(httpRequest, httpResponse, texture, format); 157 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 { 158 {
173 if (texture.Type != (sbyte)AssetType.Texture) 159 AssetBase newTexture = new AssetBase(texture.ID + "-" + format, texture.Name, (sbyte)AssetType.Texture, texture.Metadata.CreatorID);
174 { 160 newTexture.Data = ConvertTextureData(texture, format);
175 httpResponse.StatusCode = (int)System.Net.HttpStatusCode.NotFound; 161 if (newTexture.Data.Length == 0)
176 return true; 162 return false; // !!! Caller try another codec, please!
177 } 163
178 if (format == DefaultFormat) 164 newTexture.Flags = AssetFlags.Collectable;
179 { 165 newTexture.Temporary = true;
180 WriteTextureData(httpRequest, httpResponse, texture, format); 166 m_assetService.Store(newTexture);
181 return true; 167 WriteTextureData(request, response, newTexture, format);
182 } 168 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 } 169 }
197 } 170 }
198 else // it was on the cache 171 }
199 { 172 else // it was on the cache
200// m_log.DebugFormat("[GETTEXTURE]: texture was in the cache"); 173 {
201 WriteTextureData(httpRequest, httpResponse, texture, format); 174 //m_log.DebugFormat("[GETTEXTURE]: texture was in the cache");
202 return true; 175 WriteTextureData(request, response, texture, format);
203 } 176 return true;
204 } 177 }
205 178
206 // not found 179 // not found
207// m_log.Warn("[GETTEXTURE]: Texture " + textureID + " not found"); 180// m_log.Warn("[GETTEXTURE]: Texture " + textureID + " not found");
208 httpResponse.StatusCode = (int)System.Net.HttpStatusCode.NotFound;
209 return true; 181 return true;
210 } 182 }
211 183
212 private void WriteTextureData(IOSHttpRequest request, IOSHttpResponse response, AssetBase texture, string format) 184 private void WriteTextureData(Hashtable request, Hashtable response, AssetBase texture, string format)
213 { 185 {
214 string range = request.Headers.GetOne("Range"); 186 Hashtable headers = new Hashtable();
187 response["headers"] = headers;
188
189 string range = String.Empty;
190
191 if (((Hashtable)request["headers"])["range"] != null)
192 range = (string)((Hashtable)request["headers"])["range"];
193
194 else if (((Hashtable)request["headers"])["Range"] != null)
195 range = (string)((Hashtable)request["headers"])["Range"];
215 196
216 if (!String.IsNullOrEmpty(range)) // JP2's only 197 if (!String.IsNullOrEmpty(range)) // JP2's only
217 { 198 {
@@ -239,10 +220,8 @@ namespace OpenSim.Capabilities.Handlers
239 // However, if we return PartialContent (or OK) instead, the viewer will display that resolution. 220 // However, if we return PartialContent (or OK) instead, the viewer will display that resolution.
240 221
241// response.StatusCode = (int)System.Net.HttpStatusCode.RequestedRangeNotSatisfiable; 222// response.StatusCode = (int)System.Net.HttpStatusCode.RequestedRangeNotSatisfiable;
242// response.AddHeader("Content-Range", String.Format("bytes */{0}", texture.Data.Length)); 223 // viewers don't seem to handle RequestedRangeNotSatisfiable and keep retrying with same parameters
243// response.StatusCode = (int)System.Net.HttpStatusCode.OK; 224 response["int_response_code"] = (int)System.Net.HttpStatusCode.NotFound;
244 response.StatusCode = (int)System.Net.HttpStatusCode.PartialContent;
245 response.ContentType = texture.Metadata.ContentType;
246 } 225 }
247 else 226 else
248 { 227 {
@@ -257,41 +236,46 @@ namespace OpenSim.Capabilities.Handlers
257 236
258// m_log.Debug("Serving " + start + " to " + end + " of " + texture.Data.Length + " bytes for texture " + texture.ID); 237// m_log.Debug("Serving " + start + " to " + end + " of " + texture.Data.Length + " bytes for texture " + texture.ID);
259 238
260 // Always return PartialContent, even if the range covered the entire data length 239 response["content-type"] = texture.Metadata.ContentType;
261 // We were accidentally sending back 404 before in this situation 240
262 // https://issues.apache.org/bugzilla/show_bug.cgi?id=51878 supports sending 206 even if the 241 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. 242 {
264 // 243 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 244 response["bin_response_data"] = texture.Data;
266 // HTTP textures on at least Imprudence 1.4.0-beta2 to never display the final texture quality. 245 response["int_bytes"] = texture.Data.Length;
267// if (end > maxEnd) 246 }
268// response.StatusCode = (int)System.Net.HttpStatusCode.OK; 247 else
269// else 248 {
270 response.StatusCode = (int)System.Net.HttpStatusCode.PartialContent; 249 response["int_response_code"] = (int)System.Net.HttpStatusCode.PartialContent;
271 250 headers["Content-Range"] = String.Format("bytes {0}-{1}/{2}", start, end, texture.Data.Length);
272 response.ContentLength = len; 251
273 response.ContentType = texture.Metadata.ContentType; 252 byte[] d = new byte[len];
274 response.AddHeader("Content-Range", String.Format("bytes {0}-{1}/{2}", start, end, texture.Data.Length)); 253 Array.Copy(texture.Data, start, d, 0, len);
275 254 response["bin_response_data"] = d;
276 response.Body.Write(texture.Data, start, len); 255 response["int_bytes"] = len;
256 }
257// response.Body.Write(texture.Data, start, len);
277 } 258 }
278 } 259 }
279 else 260 else
280 { 261 {
281 m_log.Warn("[GETTEXTURE]: Malformed Range header: " + range); 262 m_log.Warn("[GETTEXTURE]: Malformed Range header: " + range);
282 response.StatusCode = (int)System.Net.HttpStatusCode.BadRequest; 263 response["int_response_code"] = (int)System.Net.HttpStatusCode.BadRequest;
283 } 264 }
284 } 265 }
285 else // JP2's or other formats 266 else // JP2's or other formats
286 { 267 {
287 // Full content request 268 // Full content request
288 response.StatusCode = (int)System.Net.HttpStatusCode.OK; 269 response["int_response_code"] = (int)System.Net.HttpStatusCode.OK;
289 response.ContentLength = texture.Data.Length;
290 if (format == DefaultFormat) 270 if (format == DefaultFormat)
291 response.ContentType = texture.Metadata.ContentType; 271 response["content_type"] = texture.Metadata.ContentType;
292 else 272 else
293 response.ContentType = "image/" + format; 273 response["content_type"] = "image/" + format;
294 response.Body.Write(texture.Data, 0, texture.Data.Length); 274
275 response["bin_response_data"] = texture.Data;
276 response["int_bytes"] = texture.Data.Length;
277
278// response.Body.Write(texture.Data, 0, texture.Data.Length);
295 } 279 }
296 280
297// if (response.StatusCode < 200 || response.StatusCode > 299) 281// if (response.StatusCode < 200 || response.StatusCode > 299)
@@ -423,4 +407,4 @@ namespace OpenSim.Capabilities.Handlers
423 return null; 407 return null;
424 } 408 }
425 } 409 }
426} \ No newline at end of file 410}