diff options
Diffstat (limited to '')
-rw-r--r-- | OpenSim/ApplicationPlugins/Rest/Inventory/RestAssetServices.cs | 383 |
1 files changed, 0 insertions, 383 deletions
diff --git a/OpenSim/ApplicationPlugins/Rest/Inventory/RestAssetServices.cs b/OpenSim/ApplicationPlugins/Rest/Inventory/RestAssetServices.cs deleted file mode 100644 index 4ba3d77..0000000 --- a/OpenSim/ApplicationPlugins/Rest/Inventory/RestAssetServices.cs +++ /dev/null | |||
@@ -1,383 +0,0 @@ | |||
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 | |||
28 | using System; | ||
29 | using System.Xml; | ||
30 | using OpenMetaverse; | ||
31 | using OpenSim.Framework; | ||
32 | using OpenSim.Framework.Servers; | ||
33 | using OpenSim.Framework.Servers.HttpServer; | ||
34 | |||
35 | namespace OpenSim.ApplicationPlugins.Rest.Inventory | ||
36 | { | ||
37 | public class RestAssetServices : IRest | ||
38 | { | ||
39 | private bool enabled = false; | ||
40 | private string qPrefix = "assets"; | ||
41 | |||
42 | // A simple constructor is used to handle any once-only | ||
43 | // initialization of working classes. | ||
44 | |||
45 | public RestAssetServices() | ||
46 | { | ||
47 | Rest.Log.InfoFormat("{0} Asset services initializing", MsgId); | ||
48 | Rest.Log.InfoFormat("{0} Using REST Implementation Version {1}", MsgId, Rest.Version); | ||
49 | |||
50 | // If the handler specifies a relative path for its domain | ||
51 | // then we must add the standard absolute prefix, e.g. /admin | ||
52 | |||
53 | if (!qPrefix.StartsWith(Rest.UrlPathSeparator)) | ||
54 | { | ||
55 | Rest.Log.InfoFormat("{0} Prefixing domain name ({1})", MsgId, qPrefix); | ||
56 | qPrefix = String.Format("{0}{1}{2}", Rest.Prefix, Rest.UrlPathSeparator, qPrefix); | ||
57 | Rest.Log.InfoFormat("{0} Fully qualified domain name is <{1}>", MsgId, qPrefix); | ||
58 | } | ||
59 | |||
60 | // Register interface using the fully-qualified prefix | ||
61 | |||
62 | Rest.Plugin.AddPathHandler(DoAsset, qPrefix, Allocate); | ||
63 | |||
64 | // Activate if all went OK | ||
65 | |||
66 | enabled = true; | ||
67 | |||
68 | Rest.Log.InfoFormat("{0} Asset services initialization complete", MsgId); | ||
69 | } | ||
70 | |||
71 | // Post-construction, pre-enabled initialization opportunity | ||
72 | // Not currently exploited. | ||
73 | |||
74 | public void Initialize() | ||
75 | { | ||
76 | } | ||
77 | |||
78 | // Called by the plug-in to halt REST processing. Local processing is | ||
79 | // disabled, and control blocks until all current processing has | ||
80 | // completed. No new processing will be started | ||
81 | |||
82 | public void Close() | ||
83 | { | ||
84 | enabled = false; | ||
85 | Rest.Log.InfoFormat("{0} Asset services ({1}) closing down", MsgId, qPrefix); | ||
86 | } | ||
87 | |||
88 | // Properties | ||
89 | |||
90 | internal string MsgId | ||
91 | { | ||
92 | get { return Rest.MsgId; } | ||
93 | } | ||
94 | |||
95 | #region Interface | ||
96 | |||
97 | private RequestData Allocate(OSHttpRequest request, OSHttpResponse response, string prefix) | ||
98 | { | ||
99 | return (RequestData) new AssetRequestData(request, response, prefix); | ||
100 | } | ||
101 | |||
102 | // Asset Handler | ||
103 | |||
104 | private void DoAsset(RequestData rparm) | ||
105 | { | ||
106 | if (!enabled) return; | ||
107 | |||
108 | AssetRequestData rdata = (AssetRequestData) rparm; | ||
109 | |||
110 | Rest.Log.DebugFormat("{0} REST Asset handler ({1}) ENTRY", MsgId, qPrefix); | ||
111 | |||
112 | // Now that we know this is a serious attempt to | ||
113 | // access inventory data, we should find out who | ||
114 | // is asking, and make sure they are authorized | ||
115 | // to do so. We need to validate the caller's | ||
116 | // identity before revealing anything about the | ||
117 | // status quo. Authenticate throws an exception | ||
118 | // via Fail if no identity information is present. | ||
119 | // | ||
120 | // With the present HTTP server we can't use the | ||
121 | // builtin authentication mechanisms because they | ||
122 | // would be enforced for all in-bound requests. | ||
123 | // Instead we look at the headers ourselves and | ||
124 | // handle authentication directly. | ||
125 | |||
126 | try | ||
127 | { | ||
128 | if (!rdata.IsAuthenticated) | ||
129 | { | ||
130 | rdata.Fail(Rest.HttpStatusCodeNotAuthorized, String.Format("user \"{0}\" could not be authenticated")); | ||
131 | } | ||
132 | } | ||
133 | catch (RestException e) | ||
134 | { | ||
135 | if (e.statusCode == Rest.HttpStatusCodeNotAuthorized) | ||
136 | { | ||
137 | Rest.Log.WarnFormat("{0} User not authenticated", MsgId); | ||
138 | Rest.Log.DebugFormat("{0} Authorization header: {1}", MsgId, | ||
139 | rdata.request.Headers.Get("Authorization")); | ||
140 | } | ||
141 | else | ||
142 | { | ||
143 | Rest.Log.ErrorFormat("{0} User authentication failed", MsgId); | ||
144 | Rest.Log.DebugFormat("{0} Authorization header: {1}", MsgId, | ||
145 | rdata.request.Headers.Get("Authorization")); | ||
146 | } | ||
147 | throw (e); | ||
148 | } | ||
149 | |||
150 | // Remove the prefix and what's left are the parameters. If we don't have | ||
151 | // the parameters we need, fail the request. Parameters do NOT include | ||
152 | // any supplied query values. | ||
153 | |||
154 | if (rdata.Parameters.Length > 0) | ||
155 | { | ||
156 | switch (rdata.method) | ||
157 | { | ||
158 | case "get" : | ||
159 | DoGet(rdata); | ||
160 | break; | ||
161 | case "put" : | ||
162 | DoPut(rdata); | ||
163 | break; | ||
164 | case "post" : | ||
165 | DoPost(rdata); | ||
166 | break; | ||
167 | case "delete" : | ||
168 | default : | ||
169 | Rest.Log.WarnFormat("{0} Asset: Method not supported: {1}", | ||
170 | MsgId, rdata.method); | ||
171 | rdata.Fail(Rest.HttpStatusCodeBadRequest,String.Format("method <{0}> not supported", rdata.method)); | ||
172 | break; | ||
173 | } | ||
174 | } | ||
175 | else | ||
176 | { | ||
177 | Rest.Log.WarnFormat("{0} Asset: No agent information provided", MsgId); | ||
178 | rdata.Fail(Rest.HttpStatusCodeBadRequest, "no agent information provided"); | ||
179 | } | ||
180 | |||
181 | Rest.Log.DebugFormat("{0} REST Asset handler EXIT", MsgId); | ||
182 | } | ||
183 | |||
184 | #endregion Interface | ||
185 | |||
186 | /// <summary> | ||
187 | /// The only parameter we recognize is a UUID.If an asset with this identification is | ||
188 | /// found, it's content, base-64 encoded, is returned to the client. | ||
189 | /// </summary> | ||
190 | |||
191 | private void DoGet(AssetRequestData rdata) | ||
192 | { | ||
193 | Rest.Log.DebugFormat("{0} REST Asset handler, Method = <{1}> ENTRY", MsgId, rdata.method); | ||
194 | |||
195 | if (rdata.Parameters.Length == 1) | ||
196 | { | ||
197 | UUID uuid = new UUID(rdata.Parameters[0]); | ||
198 | AssetBase asset = Rest.AssetServices.Get(uuid.ToString()); | ||
199 | |||
200 | if (asset != null) | ||
201 | { | ||
202 | Rest.Log.DebugFormat("{0} Asset located <{1}>", MsgId, rdata.Parameters[0]); | ||
203 | |||
204 | rdata.initXmlWriter(); | ||
205 | |||
206 | rdata.writer.WriteStartElement(String.Empty,"Asset",String.Empty); | ||
207 | |||
208 | rdata.writer.WriteAttributeString("id", asset.ID); | ||
209 | rdata.writer.WriteAttributeString("name", asset.Name); | ||
210 | rdata.writer.WriteAttributeString("desc", asset.Description); | ||
211 | rdata.writer.WriteAttributeString("type", asset.Type.ToString()); | ||
212 | rdata.writer.WriteAttributeString("local", asset.Local.ToString()); | ||
213 | rdata.writer.WriteAttributeString("temporary", asset.Temporary.ToString()); | ||
214 | |||
215 | rdata.writer.WriteBase64(asset.Data,0,asset.Data.Length); | ||
216 | |||
217 | rdata.writer.WriteFullEndElement(); | ||
218 | |||
219 | } | ||
220 | else | ||
221 | { | ||
222 | Rest.Log.DebugFormat("{0} Invalid parameters: <{1}>", MsgId, rdata.path); | ||
223 | rdata.Fail(Rest.HttpStatusCodeNotFound, "invalid parameters"); | ||
224 | } | ||
225 | } | ||
226 | |||
227 | rdata.Complete(); | ||
228 | rdata.Respond(String.Format("Asset <{0}> : Normal completion", rdata.method)); | ||
229 | |||
230 | } | ||
231 | |||
232 | /// <summary> | ||
233 | /// UPDATE existing item, if it exists. URI identifies the item in question. | ||
234 | /// The only parameter we recognize is a UUID. The enclosed asset data (base-64 encoded) | ||
235 | /// is decoded and stored in the database, identified by the supplied UUID. | ||
236 | /// </summary> | ||
237 | private void DoPut(AssetRequestData rdata) | ||
238 | { | ||
239 | bool modified = false; | ||
240 | bool created = false; | ||
241 | |||
242 | AssetBase asset = null; | ||
243 | |||
244 | Rest.Log.DebugFormat("{0} REST Asset handler, Method = <{1}> ENTRY", MsgId, rdata.method); | ||
245 | |||
246 | if (rdata.Parameters.Length == 1) | ||
247 | { | ||
248 | |||
249 | rdata.initXmlReader(); | ||
250 | XmlReader xml = rdata.reader; | ||
251 | |||
252 | if (!xml.ReadToFollowing("Asset")) | ||
253 | { | ||
254 | Rest.Log.DebugFormat("{0} Invalid request data: <{1}>", MsgId, rdata.path); | ||
255 | rdata.Fail(Rest.HttpStatusCodeBadRequest,"invalid request data"); | ||
256 | } | ||
257 | |||
258 | UUID uuid = new UUID(rdata.Parameters[0]); | ||
259 | asset = Rest.AssetServices.Get(uuid.ToString()); | ||
260 | |||
261 | modified = (asset != null); | ||
262 | created = !modified; | ||
263 | |||
264 | asset = new AssetBase(uuid, xml.GetAttribute("name"), SByte.Parse(xml.GetAttribute("type")), UUID.Zero.ToString()); | ||
265 | asset.Description = xml.GetAttribute("desc"); | ||
266 | asset.Local = Int32.Parse(xml.GetAttribute("local")) != 0; | ||
267 | asset.Temporary = Int32.Parse(xml.GetAttribute("temporary")) != 0; | ||
268 | asset.Data = Convert.FromBase64String(xml.ReadElementContentAsString("Asset", "")); | ||
269 | |||
270 | if (asset.ID != rdata.Parameters[0]) | ||
271 | { | ||
272 | Rest.Log.WarnFormat("{0} URI and payload disagree on UUID U:{1} vs P:{2}", | ||
273 | MsgId, rdata.Parameters[0], asset.ID); | ||
274 | } | ||
275 | |||
276 | Rest.AssetServices.Store(asset); | ||
277 | |||
278 | } | ||
279 | else | ||
280 | { | ||
281 | Rest.Log.DebugFormat("{0} Invalid parameters: <{1}>", MsgId, rdata.path); | ||
282 | rdata.Fail(Rest.HttpStatusCodeNotFound, "invalid parameters"); | ||
283 | } | ||
284 | |||
285 | if (created) | ||
286 | { | ||
287 | rdata.appendStatus(String.Format("<p> Created asset {0}, UUID {1} <p>", asset.Name, asset.FullID)); | ||
288 | rdata.Complete(Rest.HttpStatusCodeCreated); | ||
289 | } | ||
290 | else | ||
291 | { | ||
292 | if (modified) | ||
293 | { | ||
294 | rdata.appendStatus(String.Format("<p> Modified asset {0}, UUID {1} <p>", asset.Name, asset.FullID)); | ||
295 | rdata.Complete(Rest.HttpStatusCodeOK); | ||
296 | } | ||
297 | else | ||
298 | { | ||
299 | rdata.Complete(Rest.HttpStatusCodeNoContent); | ||
300 | } | ||
301 | } | ||
302 | |||
303 | rdata.Respond(String.Format("Asset {0} : Normal completion", rdata.method)); | ||
304 | |||
305 | } | ||
306 | |||
307 | /// <summary> | ||
308 | /// CREATE new item, replace if it exists. URI identifies the context for the item in question. | ||
309 | /// No parameters are required for POST, just thepayload. | ||
310 | /// </summary> | ||
311 | |||
312 | private void DoPost(AssetRequestData rdata) | ||
313 | { | ||
314 | |||
315 | bool modified = false; | ||
316 | bool created = false; | ||
317 | |||
318 | Rest.Log.DebugFormat("{0} REST Asset handler, Method = <{1}> ENTRY", MsgId, rdata.method); | ||
319 | |||
320 | if (rdata.Parameters.Length != 0) | ||
321 | { | ||
322 | Rest.Log.WarnFormat("{0} Parameters ignored <{1}>", MsgId, rdata.path); | ||
323 | Rest.Log.InfoFormat("{0} POST of an asset has no parameters", MsgId, rdata.path); | ||
324 | } | ||
325 | |||
326 | rdata.initXmlReader(); | ||
327 | XmlReader xml = rdata.reader; | ||
328 | |||
329 | if (!xml.ReadToFollowing("Asset")) | ||
330 | { | ||
331 | Rest.Log.DebugFormat("{0} Invalid request data: <{1}>", MsgId, rdata.path); | ||
332 | rdata.Fail(Rest.HttpStatusCodeBadRequest,"invalid request data"); | ||
333 | } | ||
334 | |||
335 | UUID uuid = new UUID(xml.GetAttribute("id")); | ||
336 | AssetBase asset = Rest.AssetServices.Get(uuid.ToString()); | ||
337 | |||
338 | modified = (asset != null); | ||
339 | created = !modified; | ||
340 | |||
341 | asset = new AssetBase(uuid, xml.GetAttribute("name"), SByte.Parse(xml.GetAttribute("type")), UUID.Zero.ToString()); | ||
342 | asset.Description = xml.GetAttribute("desc"); | ||
343 | asset.Local = Int32.Parse(xml.GetAttribute("local")) != 0; | ||
344 | asset.Temporary = Int32.Parse(xml.GetAttribute("temporary")) != 0; | ||
345 | asset.Data = Convert.FromBase64String(xml.ReadElementContentAsString("Asset", "")); | ||
346 | |||
347 | Rest.AssetServices.Store(asset); | ||
348 | |||
349 | if (created) | ||
350 | { | ||
351 | rdata.appendStatus(String.Format("<p> Created asset {0}, UUID {1} <p>", asset.Name, asset.FullID)); | ||
352 | rdata.Complete(Rest.HttpStatusCodeCreated); | ||
353 | } | ||
354 | else | ||
355 | { | ||
356 | if (modified) | ||
357 | { | ||
358 | rdata.appendStatus(String.Format("<p> Modified asset {0}, UUID {1} <p>", asset.Name, asset.FullID)); | ||
359 | rdata.Complete(Rest.HttpStatusCodeOK); | ||
360 | } | ||
361 | else | ||
362 | { | ||
363 | rdata.Complete(Rest.HttpStatusCodeNoContent); | ||
364 | } | ||
365 | } | ||
366 | |||
367 | rdata.Respond(String.Format("Asset {0} : Normal completion", rdata.method)); | ||
368 | |||
369 | } | ||
370 | |||
371 | /// <summary> | ||
372 | /// Asset processing has no special data area requirements. | ||
373 | /// </summary> | ||
374 | |||
375 | internal class AssetRequestData : RequestData | ||
376 | { | ||
377 | internal AssetRequestData(OSHttpRequest request, OSHttpResponse response, string prefix) | ||
378 | : base(request, response, prefix) | ||
379 | { | ||
380 | } | ||
381 | } | ||
382 | } | ||
383 | } | ||