diff --git a/OpenSim/ApplicationPlugins/Rest/Regions/GETHandler.cs b/OpenSim/ApplicationPlugins/Rest/Regions/GETHandler.cs index a319a8b5af..b89976f1ee 100644 --- a/OpenSim/ApplicationPlugins/Rest/Regions/GETHandler.cs +++ b/OpenSim/ApplicationPlugins/Rest/Regions/GETHandler.cs @@ -67,18 +67,18 @@ namespace OpenSim.ApplicationPlugins.Rest.Regions try { // param empty: regions list - if (String.IsNullOrEmpty(param)) return GetHandlerRegions(); + if (String.IsNullOrEmpty(param)) return GetHandlerRegions(httpResponse); // param not empty: specific region - return GetHandlerRegion(param); + return GetHandlerRegion(httpResponse, param); } catch (Exception e) { - return Failure("GET", e); + return Failure(httpResponse, OSHttpStatusCode.ServerErrorInternalError, "GET", e); } } - public string GetHandlerRegions() + public string GetHandlerRegions(OSHttpResponse httpResponse) { XmlWriter.WriteStartElement(String.Empty, "regions", String.Empty); foreach (Scene s in App.SceneManager.Scenes) @@ -105,7 +105,7 @@ namespace OpenSim.ApplicationPlugins.Rest.Regions return XmlWriterResult; } - public string GetHandlerRegion(string param) + public string GetHandlerRegion(OSHttpResponse httpResponse, string param) { // be resilient and don't get confused by a terminating '/' param = param.TrimEnd(new char[]{'/'}); @@ -118,7 +118,8 @@ namespace OpenSim.ApplicationPlugins.Rest.Regions Scene scene = null; App.SceneManager.TryGetScene(regionID, out scene); - if (null == scene) return Failure("GET", "cannot find region"); + if (null == scene) return Failure(httpResponse, OSHttpStatusCode.ClientErrorNotFound, + "GET", "cannot find region {0}", regionID.ToString()); RegionDetails details = new RegionDetails(scene.RegionInfo); @@ -143,25 +144,27 @@ namespace OpenSim.ApplicationPlugins.Rest.Regions switch (comps[1].ToLower()) { case "terrain": - return RegionTerrain(scene); + return RegionTerrain(httpResponse, scene); case "stats": - return RegionStats(scene); + return RegionStats(httpResponse, scene); case "prims": - return RegionPrims(scene); + return RegionPrims(httpResponse, scene); } } - return Failure("GET", "too many parameters"); + return Failure(httpResponse, OSHttpStatusCode.ClientErrorBadRequest, + "GET", "too many parameters {0}", param); } #endregion GET methods - protected string RegionTerrain(Scene scene) + protected string RegionTerrain(OSHttpResponse httpResponse, Scene scene) { - return Failure("GET", "terrain not implemented"); + return Failure(httpResponse, OSHttpStatusCode.ServerErrorNotImplemented, + "GET", "terrain not implemented"); } - protected string RegionStats(Scene scene) + protected string RegionStats(OSHttpResponse httpResponse, Scene scene) { int users = scene.GetAvatars().Count; int objects = scene.Entities.Count - users; @@ -182,9 +185,10 @@ namespace OpenSim.ApplicationPlugins.Rest.Regions return XmlWriterResult; } - protected string RegionPrims(Scene scene) + protected string RegionPrims(OSHttpResponse httpResponse, Scene scene) { - return Failure("GET", "prims not implemented"); + return Failure(httpResponse, OSHttpStatusCode.ServerErrorNotImplemented, + "GET", "prims not implemented"); } } } diff --git a/OpenSim/ApplicationPlugins/Rest/Regions/POSTHandler.cs b/OpenSim/ApplicationPlugins/Rest/Regions/POSTHandler.cs new file mode 100644 index 0000000000..00fe0d2596 --- /dev/null +++ b/OpenSim/ApplicationPlugins/Rest/Regions/POSTHandler.cs @@ -0,0 +1,101 @@ +/* +* Copyright (c) Contributors, http://opensimulator.org/ +* See CONTRIBUTORS.TXT for a full list of copyright holders. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* * Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* * Neither the name of the OpenSim Project nor the +* names of its contributors may be used to endorse or promote products +* derived from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY +* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY +* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +* +*/ + +using System; +using System.Threading; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Net; +using System.Reflection; +using System.Text.RegularExpressions; +using System.Timers; +using System.Xml; +using System.Xml.Serialization; +using libsecondlife; +using Mono.Addins; +using Nwc.XmlRpc; +using Nini.Config; +using OpenSim.Framework; +using OpenSim.Framework.Console; +using OpenSim.Framework.Servers; +using OpenSim.Framework.Communications; +using OpenSim.Region.Environment.Scenes; +using OpenSim.ApplicationPlugins.Rest; + +namespace OpenSim.ApplicationPlugins.Rest.Regions +{ + + public partial class RestRegionPlugin : RestPlugin + { + #region POST methods + public string PostHandler(string request, string path, string param, + OSHttpRequest httpRequest, OSHttpResponse httpResponse) + { + // foreach (string h in httpRequest.Headers.AllKeys) + // foreach (string v in httpRequest.Headers.GetValues(h)) + // m_log.DebugFormat("{0} IsGod: {1} -> {2}", MsgID, h, v); + + MsgID = RequestID; + m_log.DebugFormat("{0} POST path {1} param {2}", MsgID, path, param); + + try + { + // param empty: new region post + if (!IsGod(httpRequest)) + // XXX: this needs to be turned into a FailureUnauthorized(...) + return Failure(httpResponse, OSHttpStatusCode.ClientErrorUnauthorized, + "GET", "you are not god"); + + if (String.IsNullOrEmpty(param)) return CreateRegion(httpRequest, httpResponse); + + return Failure(httpResponse, OSHttpStatusCode.ClientErrorNotFound, + "POST", "url {0} not supported", param); + } + catch (Exception e) + { + return Failure(httpResponse, OSHttpStatusCode.ServerErrorInternalError, "POST", e); + } + } + + public string CreateRegion(OSHttpRequest request, OSHttpResponse response) + { + XmlWriter.WriteStartElement(String.Empty, "regions", String.Empty); + foreach (Scene s in App.SceneManager.Scenes) + { + XmlWriter.WriteStartElement(String.Empty, "uuid", String.Empty); + XmlWriter.WriteString(s.RegionInfo.RegionID.ToString()); + XmlWriter.WriteEndElement(); + } + XmlWriter.WriteEndElement(); + + return XmlWriterResult; + } + #endregion POST methods + } +} diff --git a/OpenSim/ApplicationPlugins/Rest/Regions/RestRegionPlugin.cs b/OpenSim/ApplicationPlugins/Rest/Regions/RestRegionPlugin.cs index 9b888fa77a..6d585a4d25 100644 --- a/OpenSim/ApplicationPlugins/Rest/Regions/RestRegionPlugin.cs +++ b/OpenSim/ApplicationPlugins/Rest/Regions/RestRegionPlugin.cs @@ -92,6 +92,7 @@ namespace OpenSim.ApplicationPlugins.Rest.Regions // add REST method handlers AddRestStreamHandler("GET", "/regions/", GetHandler); + AddRestStreamHandler("POST", "/regions/", PostHandler); } catch (Exception e) { diff --git a/OpenSim/ApplicationPlugins/Rest/RestPlugin.cs b/OpenSim/ApplicationPlugins/Rest/RestPlugin.cs index 4b8cdc114d..f1ca83d28e 100644 --- a/OpenSim/ApplicationPlugins/Rest/RestPlugin.cs +++ b/OpenSim/ApplicationPlugins/Rest/RestPlugin.cs @@ -66,7 +66,7 @@ namespace OpenSim.ApplicationPlugins.Rest private string _prefix; // URL prefix below // which all REST URLs // are living - private StringWriter _sw = null; + private StringWriter _sw = null; private XmlTextWriter _xw = null; private string _godkey; @@ -240,7 +240,8 @@ namespace OpenSim.ApplicationPlugins.Rest } } - private List _handlers = new List(); + private List _handlers = new List(); + private Dictionary _agents = new Dictionary(); /// /// Add a REST stream handler to the underlying HTTP server. @@ -271,14 +272,38 @@ namespace OpenSim.ApplicationPlugins.Rest /// /// name of agent handler /// agent handler method - /// true when the plugin is disabled or the agent - /// handler could not be added.. + /// false when the plugin is disabled or the agent + /// handler could not be added. Any generated exceptions are + /// allowed to drop through to the caller, i.e. ArgumentException. + /// public bool AddAgentHandler(string agentName, IHttpAgentHandler handler) { if (!IsEnabled) return false; + _agents.Add(agentName, handler); return _httpd.AddAgentHandler(agentName, handler); } + /// + /// Remove a powerful Agent handler from the underlying HTTP + /// server. + /// + /// name of agent handler + /// agent handler method + /// false when the plugin is disabled or the agent + /// handler could not be removed. Any generated exceptions are + /// allowed to drop through to the caller, i.e. KeyNotFound. + /// + public bool RemoveAgentHandler(string agentName, IHttpAgentHandler handler) + { + if (!IsEnabled) return false; + if(_agents[agentName] == handler) + { + _agents.Remove(agentName); + return _httpd.RemoveAgentHandler(agentName, handler); + } + return false; + } + /// /// Check whether the HTTP request came from god; that is, is /// the god_key as configured in the config section supplied @@ -316,19 +341,30 @@ namespace OpenSim.ApplicationPlugins.Rest _httpd.RemoveStreamHandler(h.HttpMethod, h.Path); } _handlers = null; + foreach (KeyValuePair h in _agents) + { + _httpd.RemoveAgentHandler(h.Key,h.Value); + } + _agents = null; } /// /// Return a failure message. /// /// origin of the failure message - /// failure message /// This should probably set a return code as /// well. (?) - protected string Failure(string method, string message) + protected string Failure(OSHttpResponse response, OSHttpStatusCode status, + string method, string format, params string[] msg) { - m_log.ErrorFormat("{0} {1} failed: {2}", MsgID, method, message); - return String.Format("{0}", message); + string m = String.Format(format, msg); + + response.StatusCode = (int)status; + response.StatusDescription = m; + + m_log.ErrorFormat("{0} {1} failed: {2}", MsgID, method, m); + return String.Format("{0}", m); } /// @@ -338,8 +374,14 @@ namespace OpenSim.ApplicationPlugins.Rest /// exception causing the failure message /// This should probably set a return code as /// well. (?) - public string Failure(string method, Exception e) + public string Failure(OSHttpResponse response, OSHttpStatusCode status, + string method, Exception e) { + string m = String.Format("exception occurred: {0}", e.Message); + + response.StatusCode = (int)status; + response.StatusDescription = m; + m_log.DebugFormat("{0} {1} failed: {2}", MsgID, method, e.ToString()); m_log.ErrorFormat("{0} {1} failed: {2}", MsgID, method, e.Message); diff --git a/OpenSim/Framework/Servers/BaseHttpServer.cs b/OpenSim/Framework/Servers/BaseHttpServer.cs index a5e256be19..91b57183c5 100644 --- a/OpenSim/Framework/Servers/BaseHttpServer.cs +++ b/OpenSim/Framework/Servers/BaseHttpServer.cs @@ -120,6 +120,10 @@ namespace OpenSim.Framework.Servers return false; } + // Note that the agent string is provided simply to differentiate + // the handlers - it is NOT required to be an actual agent header + // value. + public bool AddAgentHandler(string agent, IHttpAgentHandler handler) { if (!m_agentHandlers.ContainsKey(agent)) @@ -149,7 +153,7 @@ namespace OpenSim.Framework.Servers { HttpListenerContext context = (HttpListenerContext) stateinfo; - OSHttpRequest request = new OSHttpRequest(context.Request); + OSHttpRequest request = new OSHttpRequest(context.Request); OSHttpResponse response = new OSHttpResponse(context.Response); if (request.UserAgent != null) @@ -157,11 +161,11 @@ namespace OpenSim.Framework.Servers IHttpAgentHandler agentHandler; - if (TryGetAgentHandler(request.UserAgent, out agentHandler)) + if (TryGetAgentHandler(request, response, out agentHandler)) { - m_log.DebugFormat("[HTTP-AGENT] Handler located for {0}", request.UserAgent); - HandleAgentRequest(agentHandler, request, response); - return; + // m_log.DebugFormat("[HTTP-AGENT] Handler located for {0}", request.UserAgent); + if(HandleAgentRequest(agentHandler, request, response)) + return; } } @@ -301,14 +305,14 @@ namespace OpenSim.Framework.Servers } } - private bool TryGetAgentHandler(string agent, out IHttpAgentHandler agentHandler) + private bool TryGetAgentHandler(OSHttpRequest request, OSHttpResponse response, out IHttpAgentHandler agentHandler) { agentHandler = null; try { foreach(IHttpAgentHandler handler in m_agentHandlers.Values) { - if(handler.Match(agent)) + if(handler.Match(request, response)) { agentHandler = handler; return true; @@ -472,7 +476,7 @@ namespace OpenSim.Framework.Servers /// /// - private void HandleAgentRequest(IHttpAgentHandler handler, OSHttpRequest request, OSHttpResponse response) + private bool HandleAgentRequest(IHttpAgentHandler handler, OSHttpRequest request, OSHttpResponse response) { // In the case of REST, then handler is responsible for ALL aspects of @@ -480,17 +484,27 @@ namespace OpenSim.Framework.Servers try { - handler.Handle(request, response); + return handler.Handle(request, response); } catch (Exception e) { - m_log.Warn("[HTTP-AGENT]: Error - " + e.Message); - response.SendChunked = false; - response.KeepAlive = false; - response.StatusCode = 500; - response.OutputStream.Close(); + // If the handler did in fact close the stream, then this will blow + // chunks, so that that doesn;t disturb anybody we throw away any + // and all exceptions raised. We've done our best to release the + // client. + try + { + m_log.Warn("[HTTP-AGENT]: Error - " + e.Message); + response.SendChunked = false; + response.KeepAlive = false; + response.StatusCode = (int)OSHttpStatusCode.ServerErrorInternalError; + response.OutputStream.Close(); + } + catch(Exception){} } + return true; + } public void HandleHTTPRequest(OSHttpRequest request, OSHttpResponse response) @@ -498,7 +512,7 @@ namespace OpenSim.Framework.Servers switch (request.HttpMethod) { case "OPTIONS": - response.StatusCode = 200; + response.StatusCode = (int)OSHttpStatusCode.SuccessOk; return; default: @@ -599,9 +613,9 @@ namespace OpenSim.Framework.Servers // We're forgoing the usual error status codes here because the client // ignores anything but 200 and 301 - response.StatusCode = 200; + response.StatusCode = (int)OSHttpStatusCode.SuccessOk; - if (responsecode == 301) + if (responsecode == (int)OSHttpStatusCode.RedirectMovedPermanently) { response.RedirectLocation = (string)responsedata["str_redirect_location"]; response.StatusCode = responsecode; @@ -632,7 +646,7 @@ namespace OpenSim.Framework.Servers public void SendHTML404(OSHttpResponse response, string host) { // I know this statuscode is dumb, but the client doesn't respond to 404s and 500s - response.StatusCode = 200; + response.StatusCode = (int)OSHttpStatusCode.SuccessOk; response.AddHeader("Content-type", "text/html"); string responseString = GetHTTP404(host); @@ -659,7 +673,7 @@ namespace OpenSim.Framework.Servers public void SendHTML500(OSHttpResponse response) { // I know this statuscode is dumb, but the client doesn't respond to 404s and 500s - response.StatusCode = 200; + response.StatusCode = (int)OSHttpStatusCode.SuccessOk; response.AddHeader("Content-type", "text/html"); string responseString = GetHTTP500(); @@ -738,6 +752,23 @@ namespace OpenSim.Framework.Servers m_HTTPHandlers.Remove(GetHandlerKey(httpMethod, path)); } + // Remove the agent IF it is registered. Intercept the possible + // exception. + + public bool RemoveAgentHandler(string agent, IHttpAgentHandler handler) + { + try + { + if(handler == m_agentHandlers[agent]) + { + m_agentHandlers.Remove(agent); + return true; + } + } + catch(KeyNotFoundException) {} + return false; + } + public string GetHTTP404(string host) { string file = Path.Combine(Util.configDir(), "http_404.html"); diff --git a/OpenSim/Framework/Servers/IHttpAgentHandler.cs b/OpenSim/Framework/Servers/IHttpAgentHandler.cs index 9bca150369..ff3a5b9f64 100644 --- a/OpenSim/Framework/Servers/IHttpAgentHandler.cs +++ b/OpenSim/Framework/Servers/IHttpAgentHandler.cs @@ -33,7 +33,7 @@ namespace OpenSim.Framework.Servers { public interface IHttpAgentHandler { - void Handle(OSHttpRequest req, OSHttpResponse resp); - bool Match(string agent); + bool Handle(OSHttpRequest req, OSHttpResponse resp); + bool Match(OSHttpRequest req, OSHttpResponse resp); } } diff --git a/OpenSim/Framework/Servers/OSHttpStatusCodes.cs b/OpenSim/Framework/Servers/OSHttpStatusCodes.cs new file mode 100644 index 0000000000..2e001cf73a --- /dev/null +++ b/OpenSim/Framework/Servers/OSHttpStatusCodes.cs @@ -0,0 +1,168 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSim Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +namespace OpenSim.Framework.Servers +{ + /// + /// HTTP status codes (almost) as defined by W3C in + /// http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html + /// + public enum OSHttpStatusCode: int + { + // 1xx Informational status codes providing a provisional + // response. + // 100 Tells client that to keep on going sending its request + InfoContinue = 100, + // 101 Server understands request, proposes to switch to different + // application level protocol + InfoSwitchingProtocols = 101, + + + // 2xx Success codes + // 200 Request successful + SuccessOk = 200, + // 201 Request successful, new resource created + SuccessOkCreated = 201, + // 202 Request accepted, processing still on-going + SuccessOkAccepted = 202, + // 203 Request successful, meta information not authoritative + SuccessOkNonAuthoritativeInformation = 203, + // 204 Request successful, nothing to return in the body + SuccessOkNoContent = 204, + // 205 Request successful, reset displayed content + SuccessOkResetContent = 205, + // 206 Request successful, partial content returned + SuccessOkPartialContent = 206, + + // 3xx Redirect code: user agent needs to go somewhere else + // 300 Redirect: different presentation forms available, take + // a pick + RedirectMultipleChoices = 300, + // 301 Redirect: requested resource has moved and now lives + // somewhere else + RedirectMovedPermanently = 301, + // 302 Redirect: Resource temporarily somewhere else, location + // might change + RedirectFound = 302, + // 303 Redirect: See other as result of a POST + RedirectSeeOther = 303, + // 304 Redirect: Resource still the same as before + RedirectNotModified = 304, + // 305 Redirect: Resource must be accessed via proxy provided + // in location field + RedirectUseProxy = 305, + // 307 Redirect: Resource temporarily somewhere else, location + // might change + RedirectMovedTemporarily = 307, + + // 4xx Client error: the client borked the request + // 400 Client error: bad request, server does not grok what + // the client wants + ClientErrorBadRequest = 400, + // 401 Client error: the client is not authorized, response + // provides WWW-Authenticate header field with a challenge + ClientErrorUnauthorized = 401, + // 402 Client error: Payment required (reserved for future use) + ClientErrorPaymentRequired = 402, + // 403 Client error: Server understood request, will not + // deliver, do not try again. + ClientErrorForbidden = 403, + // 404 Client error: Server cannot find anything matching the + // client request. + ClientErrorNotFound = 404, + // 405 Client error: The method specified by the client in the + // request is not allowed for the resource requested + ClientErrorMethodNotAllowed = 405, + // 406 Client error: Server cannot generate suitable response + // for the resource and content characteristics requested by + // the client + ClientErrorNotAcceptable = 406, + // 407 Client error: Similar to 401, Server requests that + // client authenticate itself with the proxy first + ClientErrorProxyAuthRequired = 407, + // 408 Client error: Server got impatient with client and + // decided to give up waiting for the client's request to + // arrive + ClientErrorRequestTimeout = 408, + // 409 Client error: Server could not fulfill the request for + // a resource as there is a conflict with the current state of + // the resource but thinks client can do something about this + ClientErrorConflict = 409, + // 410 Client error: The resource has moved somewhere else, + // but server has no clue where. + ClientErrorGone = 410, + // 411 Client error: The server is picky again and insists on + // having a content-length header field in the request + ClientErrorLengthRequired = 411, + // 412 Client error: one or more preconditions supplied in the + // client's request is false + ClientErrorPreconditionFailed = 412, + // 413 Client error: For fear of reflux, the server refuses to + // swallow that much data. + ClientErrorRequestEntityToLarge = 413, + // 414 Client error: The server considers the Request-URI to + // be indecently long and refuses to even look at it. + ClientErrorRequestURITooLong = 414, + // 415 Client error: The server has no clue about the media + // type requested by the client (contrary to popular belief it + // is not a warez server) + ClientErrorUnsupportedMediaType = 415, + // 416 Client error: The requested range cannot be delivered + // by the server. + ClientErrorRequestRangeNotSatisfiable = 416, + // 417 Client error: The expectations of the client as + // expressed in one or more Expect header fields cannot be met + // by the server, the server is awfully sorry about this. + ClientErrorExpectationFailed = 417, + + // 5xx Server errors (rare) + // 500 Server error: something really strange and unexpected + // happened + ServerErrorInternalError = 500, + // 501 Server error: The server does not do the functionality + // required to carry out the client request. not at + // all. certainly not before breakfast. but also not after + // breakfast. + ServerErrorNotImplemented = 501, + // 502 Server error: While acting as a proxy or a gateway, the + // server got ditched by the upstream server and as a + // consequence regretfully cannot fulfill the client's request + ServerErrorBadGateway = 502, + // 503 Server error: Due to unforseen circumstances the server + // cannot currently deliver the service requested. Retry-After + // header might indicate when to try again. + ServerErrorServiceUnavailable = 503, + // 504 Server error: The server blames the upstream server + // for not being able to deliver the service requested and + // claims that the upstream server is too slow delivering the + // goods. + ServerErrorGatewayTimeout = 504, + // 505 Server error: The server does not support the HTTP + // version conveyed in the client's request. + ServerErrorHttpVersionNotSupported = 505, + } +}