aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/CoreModules/Avatar/Assets/GetTextureModule.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/CoreModules/Avatar/Assets/GetTextureModule.cs')
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Assets/GetTextureModule.cs220
1 files changed, 220 insertions, 0 deletions
diff --git a/OpenSim/Region/CoreModules/Avatar/Assets/GetTextureModule.cs b/OpenSim/Region/CoreModules/Avatar/Assets/GetTextureModule.cs
new file mode 100644
index 0000000..53d2cef
--- /dev/null
+++ b/OpenSim/Region/CoreModules/Avatar/Assets/GetTextureModule.cs
@@ -0,0 +1,220 @@
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 System;
29using System.Collections;
30using System.Collections.Specialized;
31using System.Reflection;
32using System.IO;
33using System.Web;
34using log4net;
35using Nini.Config;
36using OpenMetaverse;
37using OpenMetaverse.StructuredData;
38using OpenSim.Framework;
39using OpenSim.Framework.Servers;
40using OpenSim.Framework.Servers.HttpServer;
41using OpenSim.Region.Framework.Interfaces;
42using OpenSim.Region.Framework.Scenes;
43using OpenSim.Services.Interfaces;
44using Caps = OpenSim.Framework.Capabilities.Caps;
45
46namespace OpenSim.Region.CoreModules.Avatar.ObjectCaps
47{
48 #region Stream Handler
49
50 public delegate byte[] StreamHandlerCallback(string path, Stream request, OSHttpRequest httpRequest, OSHttpResponse httpResponse);
51
52 public class StreamHandler : BaseStreamHandler
53 {
54 StreamHandlerCallback m_callback;
55
56 public StreamHandler(string httpMethod, string path, StreamHandlerCallback callback)
57 : base(httpMethod, path)
58 {
59 m_callback = callback;
60 }
61
62 public override byte[] Handle(string path, Stream request, OSHttpRequest httpRequest, OSHttpResponse httpResponse)
63 {
64 return m_callback(path, request, httpRequest, httpResponse);
65 }
66 }
67
68 #endregion Stream Handler
69
70 public class GetTextureModule : IRegionModule
71 {
72 private static readonly ILog m_log =
73 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
74 private Scene m_scene;
75 private IAssetService m_assetService;
76
77 #region IRegionModule Members
78
79 public void Initialise(Scene pScene, IConfigSource pSource)
80 {
81 m_scene = pScene;
82 }
83
84 public void PostInitialise()
85 {
86 m_assetService = m_scene.RequestModuleInterface<IAssetService>();
87 m_scene.EventManager.OnRegisterCaps += RegisterCaps;
88 }
89
90 public void Close() { }
91
92 public string Name { get { return "GetTextureModule"; } }
93 public bool IsSharedModule { get { return false; } }
94
95 public void RegisterCaps(UUID agentID, Caps caps)
96 {
97 UUID capID = UUID.Random();
98
99 m_log.Info("[GETTEXTURE]: /CAPS/" + capID);
100 caps.RegisterHandler("GetTexture", new StreamHandler("GET", "/CAPS/" + capID, ProcessGetTexture));
101 }
102
103 #endregion
104
105 private byte[] ProcessGetTexture(string path, Stream request, OSHttpRequest httpRequest, OSHttpResponse httpResponse)
106 {
107 // TODO: Change this to a config option
108 const string REDIRECT_URL = null;
109
110 // Try to parse the texture ID from the request URL
111 NameValueCollection query = HttpUtility.ParseQueryString(httpRequest.Url.Query);
112 string textureStr = query.GetOne("texture_id");
113
114 if (m_assetService == null)
115 {
116 m_log.Error("[GETTEXTURE]: Cannot fetch texture " + textureStr + " without an asset service");
117 httpResponse.StatusCode = (int)System.Net.HttpStatusCode.NotFound;
118 return null;
119 }
120
121 UUID textureID;
122 if (!String.IsNullOrEmpty(textureStr) && UUID.TryParse(textureStr, out textureID))
123 {
124 AssetBase texture;
125
126 if (!String.IsNullOrEmpty(REDIRECT_URL))
127 {
128 // Only try to fetch locally cached textures. Misses are redirected
129 texture = m_assetService.GetCached(textureID.ToString());
130
131 if (texture != null)
132 {
133 SendTexture(httpRequest, httpResponse, texture);
134 }
135 else
136 {
137 string textureUrl = REDIRECT_URL + textureID.ToString();
138 m_log.Debug("[GETTEXTURE]: Redirecting texture request to " + textureUrl);
139 httpResponse.RedirectLocation = textureUrl;
140 }
141 }
142 else
143 {
144 // Fetch locally or remotely. Misses return a 404
145 texture = m_assetService.Get(textureID.ToString());
146
147 if (texture != null)
148 {
149 SendTexture(httpRequest, httpResponse, texture);
150 }
151 else
152 {
153 m_log.Warn("[GETTEXTURE]: Texture " + textureID + " not found");
154 httpResponse.StatusCode = (int)System.Net.HttpStatusCode.NotFound;
155 }
156 }
157 }
158 else
159 {
160 m_log.Warn("[GETTEXTURE]: Failed to parse a texture_id from GetTexture request: " + httpRequest.Url);
161 }
162
163 httpResponse.Send();
164 return null;
165 }
166
167 private void SendTexture(OSHttpRequest request, OSHttpResponse response, AssetBase texture)
168 {
169 string range = request.Headers.GetOne("Range");
170 if (!String.IsNullOrEmpty(range))
171 {
172 // Range request
173 int start, end;
174 if (TryParseRange(range, out start, out end))
175 {
176 end = Utils.Clamp(end, 1, texture.Data.Length);
177 start = Utils.Clamp(start, 0, end - 1);
178
179 m_log.Debug("Serving " + start + " to " + end + " of " + texture.Data.Length + " bytes for texture " + texture.ID);
180
181 if (end - start < texture.Data.Length)
182 response.StatusCode = (int)System.Net.HttpStatusCode.PartialContent;
183
184 response.ContentLength = end - start;
185 response.ContentType = texture.Metadata.ContentType;
186
187 response.Body.Write(texture.Data, start, end - start);
188 }
189 else
190 {
191 m_log.Warn("Malformed Range header: " + range);
192 response.StatusCode = (int)System.Net.HttpStatusCode.BadRequest;
193 }
194 }
195 else
196 {
197 // Full content request
198 response.ContentLength = texture.Data.Length;
199 response.ContentType = texture.Metadata.ContentType;
200 response.Body.Write(texture.Data, 0, texture.Data.Length);
201 }
202 }
203
204 private bool TryParseRange(string header, out int start, out int end)
205 {
206 if (header.StartsWith("bytes="))
207 {
208 string[] rangeValues = header.Substring(6).Split('-');
209 if (rangeValues.Length == 2)
210 {
211 if (Int32.TryParse(rangeValues[0], out start) && Int32.TryParse(rangeValues[1], out end))
212 return true;
213 }
214 }
215
216 start = end = 0;
217 return false;
218 }
219 }
220}