aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Capabilities/Handlers/GetMesh/GetMeshHandler.cs
diff options
context:
space:
mode:
authorUbitUmarov2015-09-01 11:43:07 +0100
committerUbitUmarov2015-09-01 11:43:07 +0100
commitfb78b182520fc9bb0f971afd0322029c70278ea6 (patch)
treeb4e30d383938fdeef8c92d1d1c2f44bb61d329bd /OpenSim/Capabilities/Handlers/GetMesh/GetMeshHandler.cs
parentlixo (diff)
parentMantis #7713: fixed bug introduced by 1st MOSES patch. (diff)
downloadopensim-SC-fb78b182520fc9bb0f971afd0322029c70278ea6.zip
opensim-SC-fb78b182520fc9bb0f971afd0322029c70278ea6.tar.gz
opensim-SC-fb78b182520fc9bb0f971afd0322029c70278ea6.tar.bz2
opensim-SC-fb78b182520fc9bb0f971afd0322029c70278ea6.tar.xz
Merge remote-tracking branch 'os/master'
Diffstat (limited to 'OpenSim/Capabilities/Handlers/GetMesh/GetMeshHandler.cs')
-rw-r--r--OpenSim/Capabilities/Handlers/GetMesh/GetMeshHandler.cs253
1 files changed, 253 insertions, 0 deletions
diff --git a/OpenSim/Capabilities/Handlers/GetMesh/GetMeshHandler.cs b/OpenSim/Capabilities/Handlers/GetMesh/GetMeshHandler.cs
new file mode 100644
index 0000000..6b67da1
--- /dev/null
+++ b/OpenSim/Capabilities/Handlers/GetMesh/GetMeshHandler.cs
@@ -0,0 +1,253 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
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.
26 */
27
28using log4net;
29using OpenMetaverse;
30using OpenMetaverse.Imaging;
31using OpenSim.Framework;
32using OpenSim.Framework.Servers.HttpServer;
33using OpenSim.Services.Interfaces;
34using System;
35using System.Collections.Specialized;
36using System.Drawing;
37using System.Drawing.Imaging;
38using System.IO;
39using System.Reflection;
40using System.Web;
41
42namespace OpenSim.Capabilities.Handlers
43{
44 public class GetMeshHandler : BaseStreamHandler
45 {
46 private static readonly ILog m_log =
47 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
48 private IAssetService m_assetService;
49
50 // TODO: Change this to a config option
51 private string m_RedirectURL = null;
52
53 public GetMeshHandler(string path, IAssetService assService, string name, string description, string redirectURL)
54 : base("GET", path, name, description)
55 {
56 m_assetService = assService;
57 m_RedirectURL = redirectURL;
58 if (m_RedirectURL != null && !m_RedirectURL.EndsWith("/"))
59 m_RedirectURL += "/";
60 }
61
62 protected override byte[] ProcessRequest(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
63 {
64 // Try to parse the texture ID from the request URL
65 NameValueCollection query = HttpUtility.ParseQueryString(httpRequest.Url.Query);
66 string textureStr = query.GetOne("mesh_id");
67
68 if (m_assetService == null)
69 {
70 m_log.Error("[GETMESH]: Cannot fetch mesh " + textureStr + " without an asset service");
71 httpResponse.StatusCode = (int)System.Net.HttpStatusCode.NotFound;
72 }
73
74 UUID meshID;
75 if (!String.IsNullOrEmpty(textureStr) && UUID.TryParse(textureStr, out meshID))
76 {
77 // OK, we have an array with preferred formats, possibly with only one entry
78
79 httpResponse.StatusCode = (int)System.Net.HttpStatusCode.NotFound;
80 AssetBase mesh;
81
82 if (!String.IsNullOrEmpty(m_RedirectURL))
83 {
84 // Only try to fetch locally cached meshes. Misses are redirected
85 mesh = m_assetService.GetCached(meshID.ToString());
86
87 if (mesh != null)
88 {
89 if (mesh.Type != (sbyte)AssetType.Mesh)
90 {
91 httpResponse.StatusCode = (int)System.Net.HttpStatusCode.NotFound;
92 }
93 WriteMeshData(httpRequest, httpResponse, mesh);
94 }
95 else
96 {
97 string textureUrl = m_RedirectURL + "?mesh_id="+ meshID.ToString();
98 m_log.Debug("[GETMESH]: Redirecting mesh request to " + textureUrl);
99 httpResponse.StatusCode = (int)OSHttpStatusCode.RedirectMovedPermanently;
100 httpResponse.RedirectLocation = textureUrl;
101 return null;
102 }
103 }
104 else // no redirect
105 {
106 // try the cache
107 mesh = m_assetService.GetCached(meshID.ToString());
108
109 if (mesh == null)
110 {
111 // Fetch locally or remotely. Misses return a 404
112 mesh = m_assetService.Get(meshID.ToString());
113
114 if (mesh != null)
115 {
116 if (mesh.Type != (sbyte)AssetType.Mesh)
117 {
118 httpResponse.StatusCode = (int)System.Net.HttpStatusCode.NotFound;
119 return null;
120 }
121 WriteMeshData(httpRequest, httpResponse, mesh);
122 return null;
123 }
124 }
125 else // it was on the cache
126 {
127 if (mesh.Type != (sbyte)AssetType.Mesh)
128 {
129 httpResponse.StatusCode = (int)System.Net.HttpStatusCode.NotFound;
130 return null;
131 }
132 WriteMeshData(httpRequest, httpResponse, mesh);
133 return null;
134 }
135 }
136
137 // not found
138 httpResponse.StatusCode = (int)System.Net.HttpStatusCode.NotFound;
139 return null;
140 }
141 else
142 {
143 m_log.Warn("[GETTEXTURE]: Failed to parse a mesh_id from GetMesh request: " + httpRequest.Url);
144 }
145
146 return null;
147 }
148
149 private void WriteMeshData(IOSHttpRequest request, IOSHttpResponse response, AssetBase texture)
150 {
151 string range = request.Headers.GetOne("Range");
152
153 if (!String.IsNullOrEmpty(range))
154 {
155 // Range request
156 int start, end;
157 if (TryParseRange(range, out start, out end))
158 {
159 // Before clamping start make sure we can satisfy it in order to avoid
160 // sending back the last byte instead of an error status
161 if (start >= texture.Data.Length)
162 {
163 response.StatusCode = (int)System.Net.HttpStatusCode.PartialContent;
164 response.ContentType = texture.Metadata.ContentType;
165 }
166 else
167 {
168 // Handle the case where no second range value was given. This is equivalent to requesting
169 // the rest of the entity.
170 if (end == -1)
171 end = int.MaxValue;
172
173 end = Utils.Clamp(end, 0, texture.Data.Length - 1);
174 start = Utils.Clamp(start, 0, end);
175 int len = end - start + 1;
176
177 if (0 == start && len == texture.Data.Length)
178 {
179 response.StatusCode = (int)System.Net.HttpStatusCode.OK;
180 }
181 else
182 {
183 response.StatusCode = (int)System.Net.HttpStatusCode.PartialContent;
184 response.AddHeader("Content-Range", String.Format("bytes {0}-{1}/{2}", start, end, texture.Data.Length));
185 }
186
187 response.ContentLength = len;
188 response.ContentType = "application/vnd.ll.mesh";
189
190 response.Body.Write(texture.Data, start, len);
191 }
192 }
193 else
194 {
195 m_log.Warn("[GETMESH]: Malformed Range header: " + range);
196 response.StatusCode = (int)System.Net.HttpStatusCode.BadRequest;
197 }
198 }
199 else
200 {
201 // Full content request
202 response.StatusCode = (int)System.Net.HttpStatusCode.OK;
203 response.ContentLength = texture.Data.Length;
204 response.ContentType = "application/vnd.ll.mesh";
205 response.Body.Write(texture.Data, 0, texture.Data.Length);
206 }
207 }
208
209 /// <summary>
210 /// Parse a range header.
211 /// </summary>
212 /// <remarks>
213 /// As per http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html,
214 /// this obeys range headers with two values (e.g. 533-4165) and no second value (e.g. 533-).
215 /// Where there is no value, -1 is returned.
216 /// FIXME: Need to cover the case where only a second value is specified (e.g. -4165), probably by returning -1
217 /// for start.</remarks>
218 /// <returns></returns>
219 /// <param name='header'></param>
220 /// <param name='start'>Start of the range. Undefined if this was not a number.</param>
221 /// <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>
222 private bool TryParseRange(string header, out int start, out int end)
223 {
224 start = end = 0;
225
226 if (header.StartsWith("bytes="))
227 {
228 string[] rangeValues = header.Substring(6).Split('-');
229
230 if (rangeValues.Length == 2)
231 {
232 if (!Int32.TryParse(rangeValues[0], out start))
233 return false;
234
235 string rawEnd = rangeValues[1];
236
237 if (rawEnd == "")
238 {
239 end = -1;
240 return true;
241 }
242 else if (Int32.TryParse(rawEnd, out end))
243 {
244 return true;
245 }
246 }
247 }
248
249 start = end = 0;
250 return false;
251 }
252 }
253} \ No newline at end of file