diff options
-rw-r--r-- | OpenSim/ApplicationPlugins/Rest/Regions/GETHandler.cs | 34 | ||||
-rw-r--r-- | OpenSim/ApplicationPlugins/Rest/Regions/POSTHandler.cs | 101 | ||||
-rw-r--r-- | OpenSim/ApplicationPlugins/Rest/Regions/RestRegionPlugin.cs | 1 | ||||
-rw-r--r-- | OpenSim/ApplicationPlugins/Rest/RestPlugin.cs | 60 | ||||
-rw-r--r-- | OpenSim/Framework/Servers/BaseHttpServer.cs | 69 | ||||
-rw-r--r-- | OpenSim/Framework/Servers/IHttpAgentHandler.cs | 4 | ||||
-rw-r--r-- | OpenSim/Framework/Servers/OSHttpStatusCodes.cs | 168 |
7 files changed, 392 insertions, 45 deletions
diff --git a/OpenSim/ApplicationPlugins/Rest/Regions/GETHandler.cs b/OpenSim/ApplicationPlugins/Rest/Regions/GETHandler.cs index a319a8b..b89976f 100644 --- a/OpenSim/ApplicationPlugins/Rest/Regions/GETHandler.cs +++ b/OpenSim/ApplicationPlugins/Rest/Regions/GETHandler.cs | |||
@@ -67,18 +67,18 @@ namespace OpenSim.ApplicationPlugins.Rest.Regions | |||
67 | try | 67 | try |
68 | { | 68 | { |
69 | // param empty: regions list | 69 | // param empty: regions list |
70 | if (String.IsNullOrEmpty(param)) return GetHandlerRegions(); | 70 | if (String.IsNullOrEmpty(param)) return GetHandlerRegions(httpResponse); |
71 | 71 | ||
72 | // param not empty: specific region | 72 | // param not empty: specific region |
73 | return GetHandlerRegion(param); | 73 | return GetHandlerRegion(httpResponse, param); |
74 | } | 74 | } |
75 | catch (Exception e) | 75 | catch (Exception e) |
76 | { | 76 | { |
77 | return Failure("GET", e); | 77 | return Failure(httpResponse, OSHttpStatusCode.ServerErrorInternalError, "GET", e); |
78 | } | 78 | } |
79 | } | 79 | } |
80 | 80 | ||
81 | public string GetHandlerRegions() | 81 | public string GetHandlerRegions(OSHttpResponse httpResponse) |
82 | { | 82 | { |
83 | XmlWriter.WriteStartElement(String.Empty, "regions", String.Empty); | 83 | XmlWriter.WriteStartElement(String.Empty, "regions", String.Empty); |
84 | foreach (Scene s in App.SceneManager.Scenes) | 84 | foreach (Scene s in App.SceneManager.Scenes) |
@@ -105,7 +105,7 @@ namespace OpenSim.ApplicationPlugins.Rest.Regions | |||
105 | return XmlWriterResult; | 105 | return XmlWriterResult; |
106 | } | 106 | } |
107 | 107 | ||
108 | public string GetHandlerRegion(string param) | 108 | public string GetHandlerRegion(OSHttpResponse httpResponse, string param) |
109 | { | 109 | { |
110 | // be resilient and don't get confused by a terminating '/' | 110 | // be resilient and don't get confused by a terminating '/' |
111 | param = param.TrimEnd(new char[]{'/'}); | 111 | param = param.TrimEnd(new char[]{'/'}); |
@@ -118,7 +118,8 @@ namespace OpenSim.ApplicationPlugins.Rest.Regions | |||
118 | 118 | ||
119 | Scene scene = null; | 119 | Scene scene = null; |
120 | App.SceneManager.TryGetScene(regionID, out scene); | 120 | App.SceneManager.TryGetScene(regionID, out scene); |
121 | if (null == scene) return Failure("GET", "cannot find region"); | 121 | if (null == scene) return Failure(httpResponse, OSHttpStatusCode.ClientErrorNotFound, |
122 | "GET", "cannot find region {0}", regionID.ToString()); | ||
122 | 123 | ||
123 | RegionDetails details = new RegionDetails(scene.RegionInfo); | 124 | RegionDetails details = new RegionDetails(scene.RegionInfo); |
124 | 125 | ||
@@ -143,25 +144,27 @@ namespace OpenSim.ApplicationPlugins.Rest.Regions | |||
143 | switch (comps[1].ToLower()) | 144 | switch (comps[1].ToLower()) |
144 | { | 145 | { |
145 | case "terrain": | 146 | case "terrain": |
146 | return RegionTerrain(scene); | 147 | return RegionTerrain(httpResponse, scene); |
147 | 148 | ||
148 | case "stats": | 149 | case "stats": |
149 | return RegionStats(scene); | 150 | return RegionStats(httpResponse, scene); |
150 | 151 | ||
151 | case "prims": | 152 | case "prims": |
152 | return RegionPrims(scene); | 153 | return RegionPrims(httpResponse, scene); |
153 | } | 154 | } |
154 | } | 155 | } |
155 | return Failure("GET", "too many parameters"); | 156 | return Failure(httpResponse, OSHttpStatusCode.ClientErrorBadRequest, |
157 | "GET", "too many parameters {0}", param); | ||
156 | } | 158 | } |
157 | #endregion GET methods | 159 | #endregion GET methods |
158 | 160 | ||
159 | protected string RegionTerrain(Scene scene) | 161 | protected string RegionTerrain(OSHttpResponse httpResponse, Scene scene) |
160 | { | 162 | { |
161 | return Failure("GET", "terrain not implemented"); | 163 | return Failure(httpResponse, OSHttpStatusCode.ServerErrorNotImplemented, |
164 | "GET", "terrain not implemented"); | ||
162 | } | 165 | } |
163 | 166 | ||
164 | protected string RegionStats(Scene scene) | 167 | protected string RegionStats(OSHttpResponse httpResponse, Scene scene) |
165 | { | 168 | { |
166 | int users = scene.GetAvatars().Count; | 169 | int users = scene.GetAvatars().Count; |
167 | int objects = scene.Entities.Count - users; | 170 | int objects = scene.Entities.Count - users; |
@@ -182,9 +185,10 @@ namespace OpenSim.ApplicationPlugins.Rest.Regions | |||
182 | return XmlWriterResult; | 185 | return XmlWriterResult; |
183 | } | 186 | } |
184 | 187 | ||
185 | protected string RegionPrims(Scene scene) | 188 | protected string RegionPrims(OSHttpResponse httpResponse, Scene scene) |
186 | { | 189 | { |
187 | return Failure("GET", "prims not implemented"); | 190 | return Failure(httpResponse, OSHttpStatusCode.ServerErrorNotImplemented, |
191 | "GET", "prims not implemented"); | ||
188 | } | 192 | } |
189 | } | 193 | } |
190 | } | 194 | } |
diff --git a/OpenSim/ApplicationPlugins/Rest/Regions/POSTHandler.cs b/OpenSim/ApplicationPlugins/Rest/Regions/POSTHandler.cs new file mode 100644 index 0000000..00fe0d2 --- /dev/null +++ b/OpenSim/ApplicationPlugins/Rest/Regions/POSTHandler.cs | |||
@@ -0,0 +1,101 @@ | |||
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 OpenSim 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 | |||
29 | using System; | ||
30 | using System.Threading; | ||
31 | using System.Collections; | ||
32 | using System.Collections.Generic; | ||
33 | using System.IO; | ||
34 | using System.Net; | ||
35 | using System.Reflection; | ||
36 | using System.Text.RegularExpressions; | ||
37 | using System.Timers; | ||
38 | using System.Xml; | ||
39 | using System.Xml.Serialization; | ||
40 | using libsecondlife; | ||
41 | using Mono.Addins; | ||
42 | using Nwc.XmlRpc; | ||
43 | using Nini.Config; | ||
44 | using OpenSim.Framework; | ||
45 | using OpenSim.Framework.Console; | ||
46 | using OpenSim.Framework.Servers; | ||
47 | using OpenSim.Framework.Communications; | ||
48 | using OpenSim.Region.Environment.Scenes; | ||
49 | using OpenSim.ApplicationPlugins.Rest; | ||
50 | |||
51 | namespace OpenSim.ApplicationPlugins.Rest.Regions | ||
52 | { | ||
53 | |||
54 | public partial class RestRegionPlugin : RestPlugin | ||
55 | { | ||
56 | #region POST methods | ||
57 | public string PostHandler(string request, string path, string param, | ||
58 | OSHttpRequest httpRequest, OSHttpResponse httpResponse) | ||
59 | { | ||
60 | // foreach (string h in httpRequest.Headers.AllKeys) | ||
61 | // foreach (string v in httpRequest.Headers.GetValues(h)) | ||
62 | // m_log.DebugFormat("{0} IsGod: {1} -> {2}", MsgID, h, v); | ||
63 | |||
64 | MsgID = RequestID; | ||
65 | m_log.DebugFormat("{0} POST path {1} param {2}", MsgID, path, param); | ||
66 | |||
67 | try | ||
68 | { | ||
69 | // param empty: new region post | ||
70 | if (!IsGod(httpRequest)) | ||
71 | // XXX: this needs to be turned into a FailureUnauthorized(...) | ||
72 | return Failure(httpResponse, OSHttpStatusCode.ClientErrorUnauthorized, | ||
73 | "GET", "you are not god"); | ||
74 | |||
75 | if (String.IsNullOrEmpty(param)) return CreateRegion(httpRequest, httpResponse); | ||
76 | |||
77 | return Failure(httpResponse, OSHttpStatusCode.ClientErrorNotFound, | ||
78 | "POST", "url {0} not supported", param); | ||
79 | } | ||
80 | catch (Exception e) | ||
81 | { | ||
82 | return Failure(httpResponse, OSHttpStatusCode.ServerErrorInternalError, "POST", e); | ||
83 | } | ||
84 | } | ||
85 | |||
86 | public string CreateRegion(OSHttpRequest request, OSHttpResponse response) | ||
87 | { | ||
88 | XmlWriter.WriteStartElement(String.Empty, "regions", String.Empty); | ||
89 | foreach (Scene s in App.SceneManager.Scenes) | ||
90 | { | ||
91 | XmlWriter.WriteStartElement(String.Empty, "uuid", String.Empty); | ||
92 | XmlWriter.WriteString(s.RegionInfo.RegionID.ToString()); | ||
93 | XmlWriter.WriteEndElement(); | ||
94 | } | ||
95 | XmlWriter.WriteEndElement(); | ||
96 | |||
97 | return XmlWriterResult; | ||
98 | } | ||
99 | #endregion POST methods | ||
100 | } | ||
101 | } | ||
diff --git a/OpenSim/ApplicationPlugins/Rest/Regions/RestRegionPlugin.cs b/OpenSim/ApplicationPlugins/Rest/Regions/RestRegionPlugin.cs index 9b888fa..6d585a4 100644 --- a/OpenSim/ApplicationPlugins/Rest/Regions/RestRegionPlugin.cs +++ b/OpenSim/ApplicationPlugins/Rest/Regions/RestRegionPlugin.cs | |||
@@ -92,6 +92,7 @@ namespace OpenSim.ApplicationPlugins.Rest.Regions | |||
92 | 92 | ||
93 | // add REST method handlers | 93 | // add REST method handlers |
94 | AddRestStreamHandler("GET", "/regions/", GetHandler); | 94 | AddRestStreamHandler("GET", "/regions/", GetHandler); |
95 | AddRestStreamHandler("POST", "/regions/", PostHandler); | ||
95 | } | 96 | } |
96 | catch (Exception e) | 97 | catch (Exception e) |
97 | { | 98 | { |
diff --git a/OpenSim/ApplicationPlugins/Rest/RestPlugin.cs b/OpenSim/ApplicationPlugins/Rest/RestPlugin.cs index 4b8cdc1..f1ca83d 100644 --- a/OpenSim/ApplicationPlugins/Rest/RestPlugin.cs +++ b/OpenSim/ApplicationPlugins/Rest/RestPlugin.cs | |||
@@ -66,7 +66,7 @@ namespace OpenSim.ApplicationPlugins.Rest | |||
66 | private string _prefix; // URL prefix below | 66 | private string _prefix; // URL prefix below |
67 | // which all REST URLs | 67 | // which all REST URLs |
68 | // are living | 68 | // are living |
69 | private StringWriter _sw = null; | 69 | private StringWriter _sw = null; |
70 | private XmlTextWriter _xw = null; | 70 | private XmlTextWriter _xw = null; |
71 | 71 | ||
72 | private string _godkey; | 72 | private string _godkey; |
@@ -240,7 +240,8 @@ namespace OpenSim.ApplicationPlugins.Rest | |||
240 | } | 240 | } |
241 | } | 241 | } |
242 | 242 | ||
243 | private List<RestStreamHandler> _handlers = new List<RestStreamHandler>(); | 243 | private List<RestStreamHandler> _handlers = new List<RestStreamHandler>(); |
244 | private Dictionary<string, IHttpAgentHandler> _agents = new Dictionary<string, IHttpAgentHandler>(); | ||
244 | 245 | ||
245 | /// <summary> | 246 | /// <summary> |
246 | /// Add a REST stream handler to the underlying HTTP server. | 247 | /// Add a REST stream handler to the underlying HTTP server. |
@@ -271,15 +272,39 @@ namespace OpenSim.ApplicationPlugins.Rest | |||
271 | /// </summary> | 272 | /// </summary> |
272 | /// <param name="agentName">name of agent handler</param> | 273 | /// <param name="agentName">name of agent handler</param> |
273 | /// <param name="handler">agent handler method</param> | 274 | /// <param name="handler">agent handler method</param> |
274 | /// <returns>true when the plugin is disabled or the agent | 275 | /// <returns>false when the plugin is disabled or the agent |
275 | /// handler could not be added..</returns> | 276 | /// handler could not be added. Any generated exceptions are |
277 | /// allowed to drop through to the caller, i.e. ArgumentException. | ||
278 | /// </returns> | ||
276 | public bool AddAgentHandler(string agentName, IHttpAgentHandler handler) | 279 | public bool AddAgentHandler(string agentName, IHttpAgentHandler handler) |
277 | { | 280 | { |
278 | if (!IsEnabled) return false; | 281 | if (!IsEnabled) return false; |
282 | _agents.Add(agentName, handler); | ||
279 | return _httpd.AddAgentHandler(agentName, handler); | 283 | return _httpd.AddAgentHandler(agentName, handler); |
280 | } | 284 | } |
281 | 285 | ||
282 | /// <summary> | 286 | /// <summary> |
287 | /// Remove a powerful Agent handler from the underlying HTTP | ||
288 | /// server. | ||
289 | /// </summary> | ||
290 | /// <param name="agentName">name of agent handler</param> | ||
291 | /// <param name="handler">agent handler method</param> | ||
292 | /// <returns>false when the plugin is disabled or the agent | ||
293 | /// handler could not be removed. Any generated exceptions are | ||
294 | /// allowed to drop through to the caller, i.e. KeyNotFound. | ||
295 | /// </returns> | ||
296 | public bool RemoveAgentHandler(string agentName, IHttpAgentHandler handler) | ||
297 | { | ||
298 | if (!IsEnabled) return false; | ||
299 | if(_agents[agentName] == handler) | ||
300 | { | ||
301 | _agents.Remove(agentName); | ||
302 | return _httpd.RemoveAgentHandler(agentName, handler); | ||
303 | } | ||
304 | return false; | ||
305 | } | ||
306 | |||
307 | /// <summary> | ||
283 | /// Check whether the HTTP request came from god; that is, is | 308 | /// Check whether the HTTP request came from god; that is, is |
284 | /// the god_key as configured in the config section supplied | 309 | /// the god_key as configured in the config section supplied |
285 | /// via X-OpenSim-Godkey? | 310 | /// via X-OpenSim-Godkey? |
@@ -316,19 +341,30 @@ namespace OpenSim.ApplicationPlugins.Rest | |||
316 | _httpd.RemoveStreamHandler(h.HttpMethod, h.Path); | 341 | _httpd.RemoveStreamHandler(h.HttpMethod, h.Path); |
317 | } | 342 | } |
318 | _handlers = null; | 343 | _handlers = null; |
344 | foreach (KeyValuePair<string,IHttpAgentHandler> h in _agents) | ||
345 | { | ||
346 | _httpd.RemoveAgentHandler(h.Key,h.Value); | ||
347 | } | ||
348 | _agents = null; | ||
319 | } | 349 | } |
320 | 350 | ||
321 | /// <summary> | 351 | /// <summary> |
322 | /// Return a failure message. | 352 | /// Return a failure message. |
323 | /// </summary> | 353 | /// </summary> |
324 | /// <param name="method">origin of the failure message</param> | 354 | /// <param name="method">origin of the failure message</param> |
325 | /// <param name="message>failure message</param> | 355 | /// <param name="message">failure message</param> |
326 | /// <remarks>This should probably set a return code as | 356 | /// <remarks>This should probably set a return code as |
327 | /// well. (?)</remarks> | 357 | /// well. (?)</remarks> |
328 | protected string Failure(string method, string message) | 358 | protected string Failure(OSHttpResponse response, OSHttpStatusCode status, |
359 | string method, string format, params string[] msg) | ||
329 | { | 360 | { |
330 | m_log.ErrorFormat("{0} {1} failed: {2}", MsgID, method, message); | 361 | string m = String.Format(format, msg); |
331 | return String.Format("<error>{0}</error>", message); | 362 | |
363 | response.StatusCode = (int)status; | ||
364 | response.StatusDescription = m; | ||
365 | |||
366 | m_log.ErrorFormat("{0} {1} failed: {2}", MsgID, method, m); | ||
367 | return String.Format("<error>{0}</error>", m); | ||
332 | } | 368 | } |
333 | 369 | ||
334 | /// <summary> | 370 | /// <summary> |
@@ -338,8 +374,14 @@ namespace OpenSim.ApplicationPlugins.Rest | |||
338 | /// <param name="e">exception causing the failure message</param> | 374 | /// <param name="e">exception causing the failure message</param> |
339 | /// <remarks>This should probably set a return code as | 375 | /// <remarks>This should probably set a return code as |
340 | /// well. (?)</remarks> | 376 | /// well. (?)</remarks> |
341 | public string Failure(string method, Exception e) | 377 | public string Failure(OSHttpResponse response, OSHttpStatusCode status, |
378 | string method, Exception e) | ||
342 | { | 379 | { |
380 | string m = String.Format("exception occurred: {0}", e.Message); | ||
381 | |||
382 | response.StatusCode = (int)status; | ||
383 | response.StatusDescription = m; | ||
384 | |||
343 | m_log.DebugFormat("{0} {1} failed: {2}", MsgID, method, e.ToString()); | 385 | m_log.DebugFormat("{0} {1} failed: {2}", MsgID, method, e.ToString()); |
344 | m_log.ErrorFormat("{0} {1} failed: {2}", MsgID, method, e.Message); | 386 | m_log.ErrorFormat("{0} {1} failed: {2}", MsgID, method, e.Message); |
345 | 387 | ||
diff --git a/OpenSim/Framework/Servers/BaseHttpServer.cs b/OpenSim/Framework/Servers/BaseHttpServer.cs index a5e256b..91b5718 100644 --- a/OpenSim/Framework/Servers/BaseHttpServer.cs +++ b/OpenSim/Framework/Servers/BaseHttpServer.cs | |||
@@ -120,6 +120,10 @@ namespace OpenSim.Framework.Servers | |||
120 | return false; | 120 | return false; |
121 | } | 121 | } |
122 | 122 | ||
123 | // Note that the agent string is provided simply to differentiate | ||
124 | // the handlers - it is NOT required to be an actual agent header | ||
125 | // value. | ||
126 | |||
123 | public bool AddAgentHandler(string agent, IHttpAgentHandler handler) | 127 | public bool AddAgentHandler(string agent, IHttpAgentHandler handler) |
124 | { | 128 | { |
125 | if (!m_agentHandlers.ContainsKey(agent)) | 129 | if (!m_agentHandlers.ContainsKey(agent)) |
@@ -149,7 +153,7 @@ namespace OpenSim.Framework.Servers | |||
149 | { | 153 | { |
150 | HttpListenerContext context = (HttpListenerContext) stateinfo; | 154 | HttpListenerContext context = (HttpListenerContext) stateinfo; |
151 | 155 | ||
152 | OSHttpRequest request = new OSHttpRequest(context.Request); | 156 | OSHttpRequest request = new OSHttpRequest(context.Request); |
153 | OSHttpResponse response = new OSHttpResponse(context.Response); | 157 | OSHttpResponse response = new OSHttpResponse(context.Response); |
154 | 158 | ||
155 | if (request.UserAgent != null) | 159 | if (request.UserAgent != null) |
@@ -157,11 +161,11 @@ namespace OpenSim.Framework.Servers | |||
157 | 161 | ||
158 | IHttpAgentHandler agentHandler; | 162 | IHttpAgentHandler agentHandler; |
159 | 163 | ||
160 | if (TryGetAgentHandler(request.UserAgent, out agentHandler)) | 164 | if (TryGetAgentHandler(request, response, out agentHandler)) |
161 | { | 165 | { |
162 | m_log.DebugFormat("[HTTP-AGENT] Handler located for {0}", request.UserAgent); | 166 | // m_log.DebugFormat("[HTTP-AGENT] Handler located for {0}", request.UserAgent); |
163 | HandleAgentRequest(agentHandler, request, response); | 167 | if(HandleAgentRequest(agentHandler, request, response)) |
164 | return; | 168 | return; |
165 | } | 169 | } |
166 | } | 170 | } |
167 | 171 | ||
@@ -301,14 +305,14 @@ namespace OpenSim.Framework.Servers | |||
301 | } | 305 | } |
302 | } | 306 | } |
303 | 307 | ||
304 | private bool TryGetAgentHandler(string agent, out IHttpAgentHandler agentHandler) | 308 | private bool TryGetAgentHandler(OSHttpRequest request, OSHttpResponse response, out IHttpAgentHandler agentHandler) |
305 | { | 309 | { |
306 | agentHandler = null; | 310 | agentHandler = null; |
307 | try | 311 | try |
308 | { | 312 | { |
309 | foreach(IHttpAgentHandler handler in m_agentHandlers.Values) | 313 | foreach(IHttpAgentHandler handler in m_agentHandlers.Values) |
310 | { | 314 | { |
311 | if(handler.Match(agent)) | 315 | if(handler.Match(request, response)) |
312 | { | 316 | { |
313 | agentHandler = handler; | 317 | agentHandler = handler; |
314 | return true; | 318 | return true; |
@@ -472,7 +476,7 @@ namespace OpenSim.Framework.Servers | |||
472 | /// <param name="request"></param> | 476 | /// <param name="request"></param> |
473 | /// <param name="response"></param> | 477 | /// <param name="response"></param> |
474 | 478 | ||
475 | private void HandleAgentRequest(IHttpAgentHandler handler, OSHttpRequest request, OSHttpResponse response) | 479 | private bool HandleAgentRequest(IHttpAgentHandler handler, OSHttpRequest request, OSHttpResponse response) |
476 | { | 480 | { |
477 | 481 | ||
478 | // In the case of REST, then handler is responsible for ALL aspects of | 482 | // In the case of REST, then handler is responsible for ALL aspects of |
@@ -480,17 +484,27 @@ namespace OpenSim.Framework.Servers | |||
480 | 484 | ||
481 | try | 485 | try |
482 | { | 486 | { |
483 | handler.Handle(request, response); | 487 | return handler.Handle(request, response); |
484 | } | 488 | } |
485 | catch (Exception e) | 489 | catch (Exception e) |
486 | { | 490 | { |
487 | m_log.Warn("[HTTP-AGENT]: Error - " + e.Message); | 491 | // If the handler did in fact close the stream, then this will blow |
488 | response.SendChunked = false; | 492 | // chunks, so that that doesn;t disturb anybody we throw away any |
489 | response.KeepAlive = false; | 493 | // and all exceptions raised. We've done our best to release the |
490 | response.StatusCode = 500; | 494 | // client. |
491 | response.OutputStream.Close(); | 495 | try |
496 | { | ||
497 | m_log.Warn("[HTTP-AGENT]: Error - " + e.Message); | ||
498 | response.SendChunked = false; | ||
499 | response.KeepAlive = false; | ||
500 | response.StatusCode = (int)OSHttpStatusCode.ServerErrorInternalError; | ||
501 | response.OutputStream.Close(); | ||
502 | } | ||
503 | catch(Exception){} | ||
492 | } | 504 | } |
493 | 505 | ||
506 | return true; | ||
507 | |||
494 | } | 508 | } |
495 | 509 | ||
496 | public void HandleHTTPRequest(OSHttpRequest request, OSHttpResponse response) | 510 | public void HandleHTTPRequest(OSHttpRequest request, OSHttpResponse response) |
@@ -498,7 +512,7 @@ namespace OpenSim.Framework.Servers | |||
498 | switch (request.HttpMethod) | 512 | switch (request.HttpMethod) |
499 | { | 513 | { |
500 | case "OPTIONS": | 514 | case "OPTIONS": |
501 | response.StatusCode = 200; | 515 | response.StatusCode = (int)OSHttpStatusCode.SuccessOk; |
502 | return; | 516 | return; |
503 | 517 | ||
504 | default: | 518 | default: |
@@ -599,9 +613,9 @@ namespace OpenSim.Framework.Servers | |||
599 | // We're forgoing the usual error status codes here because the client | 613 | // We're forgoing the usual error status codes here because the client |
600 | // ignores anything but 200 and 301 | 614 | // ignores anything but 200 and 301 |
601 | 615 | ||
602 | response.StatusCode = 200; | 616 | response.StatusCode = (int)OSHttpStatusCode.SuccessOk; |
603 | 617 | ||
604 | if (responsecode == 301) | 618 | if (responsecode == (int)OSHttpStatusCode.RedirectMovedPermanently) |
605 | { | 619 | { |
606 | response.RedirectLocation = (string)responsedata["str_redirect_location"]; | 620 | response.RedirectLocation = (string)responsedata["str_redirect_location"]; |
607 | response.StatusCode = responsecode; | 621 | response.StatusCode = responsecode; |
@@ -632,7 +646,7 @@ namespace OpenSim.Framework.Servers | |||
632 | public void SendHTML404(OSHttpResponse response, string host) | 646 | public void SendHTML404(OSHttpResponse response, string host) |
633 | { | 647 | { |
634 | // I know this statuscode is dumb, but the client doesn't respond to 404s and 500s | 648 | // I know this statuscode is dumb, but the client doesn't respond to 404s and 500s |
635 | response.StatusCode = 200; | 649 | response.StatusCode = (int)OSHttpStatusCode.SuccessOk; |
636 | response.AddHeader("Content-type", "text/html"); | 650 | response.AddHeader("Content-type", "text/html"); |
637 | 651 | ||
638 | string responseString = GetHTTP404(host); | 652 | string responseString = GetHTTP404(host); |
@@ -659,7 +673,7 @@ namespace OpenSim.Framework.Servers | |||
659 | public void SendHTML500(OSHttpResponse response) | 673 | public void SendHTML500(OSHttpResponse response) |
660 | { | 674 | { |
661 | // I know this statuscode is dumb, but the client doesn't respond to 404s and 500s | 675 | // I know this statuscode is dumb, but the client doesn't respond to 404s and 500s |
662 | response.StatusCode = 200; | 676 | response.StatusCode = (int)OSHttpStatusCode.SuccessOk; |
663 | response.AddHeader("Content-type", "text/html"); | 677 | response.AddHeader("Content-type", "text/html"); |
664 | 678 | ||
665 | string responseString = GetHTTP500(); | 679 | string responseString = GetHTTP500(); |
@@ -738,6 +752,23 @@ namespace OpenSim.Framework.Servers | |||
738 | m_HTTPHandlers.Remove(GetHandlerKey(httpMethod, path)); | 752 | m_HTTPHandlers.Remove(GetHandlerKey(httpMethod, path)); |
739 | } | 753 | } |
740 | 754 | ||
755 | // Remove the agent IF it is registered. Intercept the possible | ||
756 | // exception. | ||
757 | |||
758 | public bool RemoveAgentHandler(string agent, IHttpAgentHandler handler) | ||
759 | { | ||
760 | try | ||
761 | { | ||
762 | if(handler == m_agentHandlers[agent]) | ||
763 | { | ||
764 | m_agentHandlers.Remove(agent); | ||
765 | return true; | ||
766 | } | ||
767 | } | ||
768 | catch(KeyNotFoundException) {} | ||
769 | return false; | ||
770 | } | ||
771 | |||
741 | public string GetHTTP404(string host) | 772 | public string GetHTTP404(string host) |
742 | { | 773 | { |
743 | string file = Path.Combine(Util.configDir(), "http_404.html"); | 774 | string file = Path.Combine(Util.configDir(), "http_404.html"); |
diff --git a/OpenSim/Framework/Servers/IHttpAgentHandler.cs b/OpenSim/Framework/Servers/IHttpAgentHandler.cs index 9bca150..ff3a5b9 100644 --- a/OpenSim/Framework/Servers/IHttpAgentHandler.cs +++ b/OpenSim/Framework/Servers/IHttpAgentHandler.cs | |||
@@ -33,7 +33,7 @@ namespace OpenSim.Framework.Servers | |||
33 | { | 33 | { |
34 | public interface IHttpAgentHandler | 34 | public interface IHttpAgentHandler |
35 | { | 35 | { |
36 | void Handle(OSHttpRequest req, OSHttpResponse resp); | 36 | bool Handle(OSHttpRequest req, OSHttpResponse resp); |
37 | bool Match(string agent); | 37 | bool Match(OSHttpRequest req, OSHttpResponse resp); |
38 | } | 38 | } |
39 | } | 39 | } |
diff --git a/OpenSim/Framework/Servers/OSHttpStatusCodes.cs b/OpenSim/Framework/Servers/OSHttpStatusCodes.cs new file mode 100644 index 0000000..2e001cf --- /dev/null +++ b/OpenSim/Framework/Servers/OSHttpStatusCodes.cs | |||
@@ -0,0 +1,168 @@ | |||
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 OpenSim 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 | namespace OpenSim.Framework.Servers | ||
29 | { | ||
30 | /// <summary> | ||
31 | /// HTTP status codes (almost) as defined by W3C in | ||
32 | /// http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html | ||
33 | /// </summary> | ||
34 | public enum OSHttpStatusCode: int | ||
35 | { | ||
36 | // 1xx Informational status codes providing a provisional | ||
37 | // response. | ||
38 | // 100 Tells client that to keep on going sending its request | ||
39 | InfoContinue = 100, | ||
40 | // 101 Server understands request, proposes to switch to different | ||
41 | // application level protocol | ||
42 | InfoSwitchingProtocols = 101, | ||
43 | |||
44 | |||
45 | // 2xx Success codes | ||
46 | // 200 Request successful | ||
47 | SuccessOk = 200, | ||
48 | // 201 Request successful, new resource created | ||
49 | SuccessOkCreated = 201, | ||
50 | // 202 Request accepted, processing still on-going | ||
51 | SuccessOkAccepted = 202, | ||
52 | // 203 Request successful, meta information not authoritative | ||
53 | SuccessOkNonAuthoritativeInformation = 203, | ||
54 | // 204 Request successful, nothing to return in the body | ||
55 | SuccessOkNoContent = 204, | ||
56 | // 205 Request successful, reset displayed content | ||
57 | SuccessOkResetContent = 205, | ||
58 | // 206 Request successful, partial content returned | ||
59 | SuccessOkPartialContent = 206, | ||
60 | |||
61 | // 3xx Redirect code: user agent needs to go somewhere else | ||
62 | // 300 Redirect: different presentation forms available, take | ||
63 | // a pick | ||
64 | RedirectMultipleChoices = 300, | ||
65 | // 301 Redirect: requested resource has moved and now lives | ||
66 | // somewhere else | ||
67 | RedirectMovedPermanently = 301, | ||
68 | // 302 Redirect: Resource temporarily somewhere else, location | ||
69 | // might change | ||
70 | RedirectFound = 302, | ||
71 | // 303 Redirect: See other as result of a POST | ||
72 | RedirectSeeOther = 303, | ||
73 | // 304 Redirect: Resource still the same as before | ||
74 | RedirectNotModified = 304, | ||
75 | // 305 Redirect: Resource must be accessed via proxy provided | ||
76 | // in location field | ||
77 | RedirectUseProxy = 305, | ||
78 | // 307 Redirect: Resource temporarily somewhere else, location | ||
79 | // might change | ||
80 | RedirectMovedTemporarily = 307, | ||
81 | |||
82 | // 4xx Client error: the client borked the request | ||
83 | // 400 Client error: bad request, server does not grok what | ||
84 | // the client wants | ||
85 | ClientErrorBadRequest = 400, | ||
86 | // 401 Client error: the client is not authorized, response | ||
87 | // provides WWW-Authenticate header field with a challenge | ||
88 | ClientErrorUnauthorized = 401, | ||
89 | // 402 Client error: Payment required (reserved for future use) | ||
90 | ClientErrorPaymentRequired = 402, | ||
91 | // 403 Client error: Server understood request, will not | ||
92 | // deliver, do not try again. | ||
93 | ClientErrorForbidden = 403, | ||
94 | // 404 Client error: Server cannot find anything matching the | ||
95 | // client request. | ||
96 | ClientErrorNotFound = 404, | ||
97 | // 405 Client error: The method specified by the client in the | ||
98 | // request is not allowed for the resource requested | ||
99 | ClientErrorMethodNotAllowed = 405, | ||
100 | // 406 Client error: Server cannot generate suitable response | ||
101 | // for the resource and content characteristics requested by | ||
102 | // the client | ||
103 | ClientErrorNotAcceptable = 406, | ||
104 | // 407 Client error: Similar to 401, Server requests that | ||
105 | // client authenticate itself with the proxy first | ||
106 | ClientErrorProxyAuthRequired = 407, | ||
107 | // 408 Client error: Server got impatient with client and | ||
108 | // decided to give up waiting for the client's request to | ||
109 | // arrive | ||
110 | ClientErrorRequestTimeout = 408, | ||
111 | // 409 Client error: Server could not fulfill the request for | ||
112 | // a resource as there is a conflict with the current state of | ||
113 | // the resource but thinks client can do something about this | ||
114 | ClientErrorConflict = 409, | ||
115 | // 410 Client error: The resource has moved somewhere else, | ||
116 | // but server has no clue where. | ||
117 | ClientErrorGone = 410, | ||
118 | // 411 Client error: The server is picky again and insists on | ||
119 | // having a content-length header field in the request | ||
120 | ClientErrorLengthRequired = 411, | ||
121 | // 412 Client error: one or more preconditions supplied in the | ||
122 | // client's request is false | ||
123 | ClientErrorPreconditionFailed = 412, | ||
124 | // 413 Client error: For fear of reflux, the server refuses to | ||
125 | // swallow that much data. | ||
126 | ClientErrorRequestEntityToLarge = 413, | ||
127 | // 414 Client error: The server considers the Request-URI to | ||
128 | // be indecently long and refuses to even look at it. | ||
129 | ClientErrorRequestURITooLong = 414, | ||
130 | // 415 Client error: The server has no clue about the media | ||
131 | // type requested by the client (contrary to popular belief it | ||
132 | // is not a warez server) | ||
133 | ClientErrorUnsupportedMediaType = 415, | ||
134 | // 416 Client error: The requested range cannot be delivered | ||
135 | // by the server. | ||
136 | ClientErrorRequestRangeNotSatisfiable = 416, | ||
137 | // 417 Client error: The expectations of the client as | ||
138 | // expressed in one or more Expect header fields cannot be met | ||
139 | // by the server, the server is awfully sorry about this. | ||
140 | ClientErrorExpectationFailed = 417, | ||
141 | |||
142 | // 5xx Server errors (rare) | ||
143 | // 500 Server error: something really strange and unexpected | ||
144 | // happened | ||
145 | ServerErrorInternalError = 500, | ||
146 | // 501 Server error: The server does not do the functionality | ||
147 | // required to carry out the client request. not at | ||
148 | // all. certainly not before breakfast. but also not after | ||
149 | // breakfast. | ||
150 | ServerErrorNotImplemented = 501, | ||
151 | // 502 Server error: While acting as a proxy or a gateway, the | ||
152 | // server got ditched by the upstream server and as a | ||
153 | // consequence regretfully cannot fulfill the client's request | ||
154 | ServerErrorBadGateway = 502, | ||
155 | // 503 Server error: Due to unforseen circumstances the server | ||
156 | // cannot currently deliver the service requested. Retry-After | ||
157 | // header might indicate when to try again. | ||
158 | ServerErrorServiceUnavailable = 503, | ||
159 | // 504 Server error: The server blames the upstream server | ||
160 | // for not being able to deliver the service requested and | ||
161 | // claims that the upstream server is too slow delivering the | ||
162 | // goods. | ||
163 | ServerErrorGatewayTimeout = 504, | ||
164 | // 505 Server error: The server does not support the HTTP | ||
165 | // version conveyed in the client's request. | ||
166 | ServerErrorHttpVersionNotSupported = 505, | ||
167 | } | ||
168 | } | ||