From ec0d2c28fa04102ecbad4c5660efecbb970201dd Mon Sep 17 00:00:00 2001 From: Melanie Thielker Date: Mon, 4 May 2009 20:19:21 +0000 Subject: [PATCH] Committing the changed tree --- .../Framework/Servers/BaseOpenSimServer.cs | 510 ++++++ .../Servers/CachedGetAssetStreamHandler.cs | 218 +++ OpenSim/Framework/Servers/CheckSumServer.cs | 26 + .../Servers/GetAssetStreamHandler.cs | 217 +++ .../Servers/HttpServer/BaseHTTPHandler.cs | 41 + .../Servers/HttpServer/BaseHttpServer.cs | 1626 +++++++++++++++++ .../Servers/HttpServer/BaseRequestHandler.cs | 71 + .../Servers/HttpServer/BaseStreamHandler.cs | 41 + .../Servers/HttpServer/BinaryStreamHandler.cs | 73 + .../Servers/HttpServer/GenericHTTPMethod.cs | 33 + .../Interfaces/IHttpAgentHandler.cs | 35 + .../HttpServer/Interfaces/IHttpServer.cs | 126 ++ .../HttpServer/Interfaces/IStreamHandler.cs | 61 + ...penSim.Framework.Servers.Interfaces.csproj | 120 ++ ...m.Framework.Servers.Interfaces.csproj.user | 12 + ...Sim.Framework.Servers.Interfaces.dll.build | 54 + .../OpenSim.Framework.Servers.Interfaces.mdp | 34 + .../Servers/HttpServer/LLSDMethod.cs | 34 + .../Servers/HttpServer/LLSDMethodString.cs | 33 + .../Servers/HttpServer/OSHttpHandler.cs | 183 ++ .../Servers/HttpServer/OSHttpHttpHandler.cs | 145 ++ .../Servers/HttpServer/OSHttpRequest.cs | 228 +++ .../Servers/HttpServer/OSHttpRequestPump.cs | 298 +++ .../Servers/HttpServer/OSHttpRequestQueue.cs | 68 + .../Servers/HttpServer/OSHttpResponse.cs | 302 +++ .../Servers/HttpServer/OSHttpServer.cs | 210 +++ .../Servers/HttpServer/OSHttpStatusCodes.cs | 170 ++ .../Servers/HttpServer/OSHttpXmlRpcHandler.cs | 180 ++ ...penSim.Framework.Servers.HttpServer.csproj | 180 ++ ...m.Framework.Servers.HttpServer.csproj.user | 12 + ...Sim.Framework.Servers.HttpServer.dll.build | 74 + .../OpenSim.Framework.Servers.HttpServer.mdp | 54 + .../HttpServer/RestDeserialiseHandler.cs | 66 + .../Servers/HttpServer/RestHTTPHandler.cs | 56 + .../Servers/HttpServer/RestMethod.cs | 32 + .../Servers/HttpServer/RestObjectPoster.cs | 84 + .../HttpServer/RestObjectPosterResponse.cs | 107 ++ .../Servers/HttpServer/RestSessionService.cs | 291 +++ .../Servers/HttpServer/RestStreamHandler.cs | 61 + .../HttpServer/SynchronousRestObjectPoster.cs | 83 + .../Servers/HttpServer/XmlRpcMethod.cs | 33 + .../OpenSim.Framework.Servers.HttpServer.dll | Bin 0 -> 41472 bytes ...enSim.Framework.Servers.HttpServer.dll.mdb | Bin 0 -> 14486 bytes .../Framework/Servers/MessageServerInfo.cs | 48 + .../Servers/PostAssetStreamHandler.cs | 72 + .../Framework/Servers/Tests/OSHttpTests.cs | 394 ++++ OpenSim/Framework/Servers/VersionInfo.cs | 53 + 47 files changed, 6849 insertions(+) create mode 100644 OpenSim/Framework/Servers/BaseOpenSimServer.cs create mode 100644 OpenSim/Framework/Servers/CachedGetAssetStreamHandler.cs create mode 100644 OpenSim/Framework/Servers/CheckSumServer.cs create mode 100644 OpenSim/Framework/Servers/GetAssetStreamHandler.cs create mode 100644 OpenSim/Framework/Servers/HttpServer/BaseHTTPHandler.cs create mode 100644 OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs create mode 100644 OpenSim/Framework/Servers/HttpServer/BaseRequestHandler.cs create mode 100644 OpenSim/Framework/Servers/HttpServer/BaseStreamHandler.cs create mode 100644 OpenSim/Framework/Servers/HttpServer/BinaryStreamHandler.cs create mode 100644 OpenSim/Framework/Servers/HttpServer/GenericHTTPMethod.cs create mode 100644 OpenSim/Framework/Servers/HttpServer/Interfaces/IHttpAgentHandler.cs create mode 100644 OpenSim/Framework/Servers/HttpServer/Interfaces/IHttpServer.cs create mode 100644 OpenSim/Framework/Servers/HttpServer/Interfaces/IStreamHandler.cs create mode 100644 OpenSim/Framework/Servers/HttpServer/Interfaces/OpenSim.Framework.Servers.Interfaces.csproj create mode 100644 OpenSim/Framework/Servers/HttpServer/Interfaces/OpenSim.Framework.Servers.Interfaces.csproj.user create mode 100644 OpenSim/Framework/Servers/HttpServer/Interfaces/OpenSim.Framework.Servers.Interfaces.dll.build create mode 100644 OpenSim/Framework/Servers/HttpServer/Interfaces/OpenSim.Framework.Servers.Interfaces.mdp create mode 100644 OpenSim/Framework/Servers/HttpServer/LLSDMethod.cs create mode 100644 OpenSim/Framework/Servers/HttpServer/LLSDMethodString.cs create mode 100644 OpenSim/Framework/Servers/HttpServer/OSHttpHandler.cs create mode 100644 OpenSim/Framework/Servers/HttpServer/OSHttpHttpHandler.cs create mode 100644 OpenSim/Framework/Servers/HttpServer/OSHttpRequest.cs create mode 100644 OpenSim/Framework/Servers/HttpServer/OSHttpRequestPump.cs create mode 100644 OpenSim/Framework/Servers/HttpServer/OSHttpRequestQueue.cs create mode 100644 OpenSim/Framework/Servers/HttpServer/OSHttpResponse.cs create mode 100644 OpenSim/Framework/Servers/HttpServer/OSHttpServer.cs create mode 100644 OpenSim/Framework/Servers/HttpServer/OSHttpStatusCodes.cs create mode 100644 OpenSim/Framework/Servers/HttpServer/OSHttpXmlRpcHandler.cs create mode 100644 OpenSim/Framework/Servers/HttpServer/OpenSim.Framework.Servers.HttpServer.csproj create mode 100644 OpenSim/Framework/Servers/HttpServer/OpenSim.Framework.Servers.HttpServer.csproj.user create mode 100644 OpenSim/Framework/Servers/HttpServer/OpenSim.Framework.Servers.HttpServer.dll.build create mode 100644 OpenSim/Framework/Servers/HttpServer/OpenSim.Framework.Servers.HttpServer.mdp create mode 100644 OpenSim/Framework/Servers/HttpServer/RestDeserialiseHandler.cs create mode 100644 OpenSim/Framework/Servers/HttpServer/RestHTTPHandler.cs create mode 100644 OpenSim/Framework/Servers/HttpServer/RestMethod.cs create mode 100644 OpenSim/Framework/Servers/HttpServer/RestObjectPoster.cs create mode 100644 OpenSim/Framework/Servers/HttpServer/RestObjectPosterResponse.cs create mode 100644 OpenSim/Framework/Servers/HttpServer/RestSessionService.cs create mode 100644 OpenSim/Framework/Servers/HttpServer/RestStreamHandler.cs create mode 100644 OpenSim/Framework/Servers/HttpServer/SynchronousRestObjectPoster.cs create mode 100644 OpenSim/Framework/Servers/HttpServer/XmlRpcMethod.cs create mode 100755 OpenSim/Framework/Servers/HttpServer/bin/Debug/OpenSim.Framework.Servers.HttpServer.dll create mode 100644 OpenSim/Framework/Servers/HttpServer/bin/Debug/OpenSim.Framework.Servers.HttpServer.dll.mdb create mode 100644 OpenSim/Framework/Servers/MessageServerInfo.cs create mode 100644 OpenSim/Framework/Servers/PostAssetStreamHandler.cs create mode 100644 OpenSim/Framework/Servers/Tests/OSHttpTests.cs create mode 100644 OpenSim/Framework/Servers/VersionInfo.cs diff --git a/OpenSim/Framework/Servers/BaseOpenSimServer.cs b/OpenSim/Framework/Servers/BaseOpenSimServer.cs new file mode 100644 index 0000000000..7ab5c33e26 --- /dev/null +++ b/OpenSim/Framework/Servers/BaseOpenSimServer.cs @@ -0,0 +1,510 @@ +/* + * 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.Collections.Generic; +using System.IO; +using System.Reflection; +using System.Text; +using System.Threading; +using System.Timers; +using log4net; +using log4net.Appender; +using log4net.Core; +using log4net.Repository; +using OpenSim.Framework.Console; +using OpenSim.Framework.Servers; +using OpenSim.Framework.Servers.HttpServer; +using OpenSim.Framework.Statistics; +using Timer=System.Timers.Timer; + +using OpenMetaverse; +using OpenMetaverse.StructuredData; + + +namespace OpenSim.Framework.Servers +{ + /// + /// Common base for the main OpenSimServers (user, grid, inventory, region, etc) + /// + public abstract class BaseOpenSimServer + { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + /// + /// This will control a periodic log printout of the current 'show stats' (if they are active) for this + /// server. + /// + private Timer m_periodicDiagnosticsTimer = new Timer(60 * 60 * 1000); + + protected CommandConsole m_console; + protected OpenSimAppender m_consoleAppender; + protected IAppender m_logFileAppender = null; + + /// + /// Time at which this server was started + /// + protected DateTime m_startuptime; + + /// + /// Record the initial startup directory for info purposes + /// + protected string m_startupDirectory = Environment.CurrentDirectory; + + /// + /// Server version information. Usually VersionInfo + information about svn revision, operating system, etc. + /// + protected string m_version; + + protected string m_pidFile = String.Empty; + + /// + /// Random uuid for private data + /// + protected string m_osSecret = String.Empty; + + protected BaseHttpServer m_httpServer; + public BaseHttpServer HttpServer + { + get { return m_httpServer; } + } + + /// + /// Holds the non-viewer statistics collection object for this service/server + /// + protected IStatsCollector m_stats; + + public BaseOpenSimServer() + { + m_startuptime = DateTime.Now; + m_version = VersionInfo.Version; + + // Random uuid for private data + m_osSecret = UUID.Random().ToString(); + + m_periodicDiagnosticsTimer.Elapsed += new ElapsedEventHandler(LogDiagnostics); + m_periodicDiagnosticsTimer.Enabled = true; + + // Add ourselves to thread monitoring. This thread will go on to become the console listening thread + Thread.CurrentThread.Name = "ConsoleThread"; + ThreadTracker.Add(Thread.CurrentThread); + + ILoggerRepository repository = LogManager.GetRepository(); + IAppender[] appenders = repository.GetAppenders(); + + foreach (IAppender appender in appenders) + { + if (appender.Name == "LogFileAppender") + { + m_logFileAppender = appender; + } + } + + } + + /// + /// Must be overriden by child classes for their own server specific startup behaviour. + /// + protected virtual void StartupSpecific() + { + if (m_console != null) + { + ILoggerRepository repository = LogManager.GetRepository(); + IAppender[] appenders = repository.GetAppenders(); + + foreach (IAppender appender in appenders) + { + if (appender.Name == "Console") + { + m_consoleAppender = (OpenSimAppender)appender; + break; + } + } + + if (null == m_consoleAppender) + { + Notice("No appender named Console found (see the log4net config file for this executable)!"); + } + else + { + m_consoleAppender.Console = m_console; + + // If there is no threshold set then the threshold is effectively everything. + if (null == m_consoleAppender.Threshold) + m_consoleAppender.Threshold = Level.All; + + Notice(String.Format("Console log level is {0}", m_consoleAppender.Threshold)); + } + + m_console.Commands.AddCommand("base", false, "quit", + "quit", + "Quit the application", HandleQuit); + + m_console.Commands.AddCommand("base", false, "shutdown", + "shutdown", + "Quit the application", HandleQuit); + + m_console.Commands.AddCommand("base", false, "set log level", + "set log level ", + "Set the console logging level", HandleLogLevel); + + m_console.Commands.AddCommand("base", false, "show info", + "show info", + "Show general information", HandleShow); + + m_console.Commands.AddCommand("base", false, "show stats", + "show stats", + "Show statistics", HandleShow); + + m_console.Commands.AddCommand("base", false, "show threads", + "show threads", + "Show thread status", HandleShow); + + m_console.Commands.AddCommand("base", false, "show uptime", + "show uptime", + "Show server uptime", HandleShow); + + m_console.Commands.AddCommand("base", false, "show version", + "show version", + "Show server version", HandleShow); + } + } + + /// + /// Should be overriden and referenced by descendents if they need to perform extra shutdown processing + /// + public virtual void ShutdownSpecific() {} + + /// + /// Provides a list of help topics that are available. Overriding classes should append their topics to the + /// information returned when the base method is called. + /// + /// + /// + /// A list of strings that represent different help topics on which more information is available + /// + protected virtual List GetHelpTopics() { return new List(); } + + /// + /// Print statistics to the logfile, if they are active + /// + protected void LogDiagnostics(object source, ElapsedEventArgs e) + { + StringBuilder sb = new StringBuilder("DIAGNOSTICS\n\n"); + sb.Append(GetUptimeReport()); + + if (m_stats != null) + { + sb.Append(m_stats.Report()); + } + + sb.Append(Environment.NewLine); + sb.Append(GetThreadsReport()); + + m_log.Debug(sb); + } + + /// + /// Get a report about the registered threads in this server. + /// + protected string GetThreadsReport() + { + StringBuilder sb = new StringBuilder(); + + List threads = ThreadTracker.GetThreads(); + if (threads == null) + { + sb.Append("Thread tracking is only enabled in DEBUG mode."); + } + else + { + sb.Append(threads.Count + " threads are being tracked:" + Environment.NewLine); + foreach (Thread t in threads) + { + if (t.IsAlive) + { + sb.Append( + "ID: " + t.ManagedThreadId + ", Name: " + t.Name + ", Alive: " + t.IsAlive + + ", Pri: " + t.Priority + ", State: " + t.ThreadState + Environment.NewLine); + } + else + { + try + { + sb.Append("ID: " + t.ManagedThreadId + ", Name: " + t.Name + ", DEAD" + Environment.NewLine); + } + catch + { + sb.Append("THREAD ERROR" + Environment.NewLine); + } + } + } + } + + return sb.ToString(); + } + + /// + /// Return a report about the uptime of this server + /// + /// + protected string GetUptimeReport() + { + StringBuilder sb = new StringBuilder(String.Format("Time now is {0}\n", DateTime.Now)); + sb.Append(String.Format("Server has been running since {0}, {1}\n", m_startuptime.DayOfWeek, m_startuptime)); + sb.Append(String.Format("That is an elapsed time of {0}\n", DateTime.Now - m_startuptime)); + + return sb.ToString(); + } + + /// + /// Performs initialisation of the scene, such as loading configuration from disk. + /// + public virtual void Startup() + { + m_log.Info("[STARTUP]: Beginning startup processing"); + + EnhanceVersionInformation(); + + m_log.Info("[STARTUP]: Version: " + m_version + "\n"); + + StartupSpecific(); + + TimeSpan timeTaken = DateTime.Now - m_startuptime; + + m_log.InfoFormat("[STARTUP]: Startup took {0}m {1}s", timeTaken.Minutes, timeTaken.Seconds); + } + + /// + /// Should be overriden and referenced by descendents if they need to perform extra shutdown processing + /// + public virtual void Shutdown() + { + ShutdownSpecific(); + + m_log.Info("[SHUTDOWN]: Shutdown processing on main thread complete. Exiting..."); + RemovePIDFile(); + + Environment.Exit(0); + } + + private void HandleQuit(string module, string[] args) + { + Shutdown(); + } + + private void HandleLogLevel(string module, string[] cmd) + { + if (null == m_consoleAppender) + { + Notice("No appender named Console found (see the log4net config file for this executable)!"); + return; + } + + string rawLevel = cmd[3]; + + ILoggerRepository repository = LogManager.GetRepository(); + Level consoleLevel = repository.LevelMap[rawLevel]; + + if (consoleLevel != null) + m_consoleAppender.Threshold = consoleLevel; + else + Notice( + String.Format( + "{0} is not a valid logging level. Valid logging levels are ALL, DEBUG, INFO, WARN, ERROR, FATAL, OFF", + rawLevel)); + + Notice(String.Format("Console log level is {0}", m_consoleAppender.Threshold)); + } + + /// + /// Show help information + /// + /// + protected virtual void ShowHelp(string[] helpArgs) + { + Notice(""); + + if (helpArgs.Length == 0) + { + Notice("set log level [level] - change the console logging level only. For example, off or debug."); + Notice("show info - show server information (e.g. startup path)."); + + if (m_stats != null) + Notice("show stats - show statistical information for this server"); + + Notice("show threads - list tracked threads"); + Notice("show uptime - show server startup time and uptime."); + Notice("show version - show server version."); + Notice(""); + + return; + } + } + + public virtual void HandleShow(string module, string[] cmd) + { + List args = new List(cmd); + + args.RemoveAt(0); + + string[] showParams = args.ToArray(); + + switch (showParams[0]) + { + case "info": + Notice("Version: " + m_version); + Notice("Startup directory: " + m_startupDirectory); + break; + + case "stats": + if (m_stats != null) + Notice(m_stats.Report()); + break; + + case "threads": + Notice(GetThreadsReport()); + break; + + case "uptime": + Notice(GetUptimeReport()); + break; + + case "version": + Notice( + String.Format( + "Version: {0} (interface version {1})", m_version, VersionInfo.MajorInterfaceVersion)); + break; + } + } + + /// + /// Console output is only possible if a console has been established. + /// That is something that cannot be determined within this class. So + /// all attempts to use the console MUST be verified. + /// + protected void Notice(string msg) + { + if (m_console != null) + { + m_console.Notice(msg); + } + } + + /// + /// Enhance the version string with extra information if it's available. + /// + protected void EnhanceVersionInformation() + { + string buildVersion = string.Empty; + + // Add subversion revision information if available + // Try file "svn_revision" in the current directory first, then the .svn info. + // This allows to make the revision available in simulators not running from the source tree. + // FIXME: Making an assumption about the directory we're currently in - we do this all over the place + // elsewhere as well + string svnRevisionFileName = "svn_revision"; + string svnFileName = ".svn/entries"; + string inputLine; + int strcmp; + + if (File.Exists(svnRevisionFileName)) + { + StreamReader RevisionFile = File.OpenText(svnRevisionFileName); + buildVersion = RevisionFile.ReadLine(); + buildVersion.Trim(); + RevisionFile.Close(); + } + + if (string.IsNullOrEmpty(buildVersion) && File.Exists(svnFileName)) + { + StreamReader EntriesFile = File.OpenText(svnFileName); + inputLine = EntriesFile.ReadLine(); + while (inputLine != null) + { + // using the dir svn revision at the top of entries file + strcmp = String.Compare(inputLine, "dir"); + if (strcmp == 0) + { + buildVersion = EntriesFile.ReadLine(); + break; + } + else + { + inputLine = EntriesFile.ReadLine(); + } + } + EntriesFile.Close(); + } + + m_version += string.IsNullOrEmpty(buildVersion) ? " " : ("." + buildVersion + " ").Substring(0, 6); + } + + protected void CreatePIDFile(string path) + { + try + { + string pidstring = System.Diagnostics.Process.GetCurrentProcess().Id.ToString(); + FileStream fs = File.Create(path); + System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding(); + Byte[] buf = enc.GetBytes(pidstring); + fs.Write(buf, 0, buf.Length); + fs.Close(); + m_pidFile = path; + } + catch (Exception) + { + } + } + + public string osSecret { + // Secret uuid for the simulator + get { return m_osSecret; } + + } + + public string StatReport(OSHttpRequest httpRequest) + { + return m_stats.XReport((DateTime.Now - m_startuptime).ToString() , m_version ); + } + + protected void RemovePIDFile() + { + if (m_pidFile != String.Empty) + { + try + { + File.Delete(m_pidFile); + m_pidFile = String.Empty; + } + catch (Exception) + { + } + } + } + } +} diff --git a/OpenSim/Framework/Servers/CachedGetAssetStreamHandler.cs b/OpenSim/Framework/Servers/CachedGetAssetStreamHandler.cs new file mode 100644 index 0000000000..39041df0cc --- /dev/null +++ b/OpenSim/Framework/Servers/CachedGetAssetStreamHandler.cs @@ -0,0 +1,218 @@ +/* + * 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 OpenSimulator 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.IO; +using System.Reflection; +using System.Text; +using System.Text.RegularExpressions; +using System.Xml; +using System.Xml.Serialization; +using log4net; +using OpenMetaverse; +using OpenSim.Data; +using OpenSim.Framework; +using OpenSim.Framework.Servers; +using OpenSim.Framework.Servers.HttpServer; +using OpenSim.Framework.Statistics; +using System.Net; + +namespace OpenSim.Framework.Servers +{ + public class CachedGetAssetStreamHandler : BaseStreamHandler + { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + // private OpenAsset_Main m_assetManager; + private IAssetCache m_assetProvider; + + /// + /// Constructor. + /// + /// + /// + public CachedGetAssetStreamHandler(IAssetCache assetProvider) + : base("GET", "/assets") + { + m_log.Info("[REST]: In Get Request"); + // m_assetManager = assetManager; + m_assetProvider = assetProvider; + } + + public override byte[] Handle(string path, Stream request, + OSHttpRequest httpRequest, OSHttpResponse httpResponse) + { + string param = GetParam(path); + byte[] result = new byte[] { }; + + string[] p = param.Split(new char[] { '/', '?', '&' }, StringSplitOptions.RemoveEmptyEntries); + + if (p.Length > 0) + { + UUID assetID = UUID.Zero; + + if (!UUID.TryParse(p[0], out assetID)) + { + m_log.InfoFormat( + "[REST]: GET:/asset ignoring request with malformed UUID {0}", p[0]); + return result; + } + + if (StatsManager.AssetStats != null) + StatsManager.AssetStats.AddRequest(); + + AssetBase asset = m_assetProvider.GetAsset(assetID,true); // TODO IsTexture should be deduced from loaded asset. It is not used in this case. + + if (asset != null) + { +// if (asset.ContainsReferences) +// { +// asset.Data = ProcessOutgoingAssetData(asset.Data); +// } + if (p.Length > 1 && p[1] == "data") + { + httpResponse.StatusCode = (int)HttpStatusCode.OK; + httpResponse.ContentType = SLAssetTypeToContentType(asset.Type); + result = asset.Data; + } + else + { + XmlSerializer xs = new XmlSerializer(typeof(AssetBase)); + MemoryStream ms = new MemoryStream(); + XmlTextWriter xw = new XmlTextWriter(ms, Encoding.UTF8); + xw.Formatting = Formatting.Indented; + xs.Serialize(xw, asset); + xw.Flush(); + + ms.Seek(0, SeekOrigin.Begin); + //StreamReader sr = new StreamReader(ms); + + result = ms.GetBuffer(); + + Array.Resize(ref result, (int)ms.Length); + } + } + else + { + if (StatsManager.AssetStats != null) + StatsManager.AssetStats.AddNotFoundRequest(); + + m_log.InfoFormat("[REST]: GET:/asset failed to find {0}", assetID); + } + } + + return result; + } + + // private byte[] ProcessOutgoingAssetData(byte[] assetData) + // { + // string data = Encoding.ASCII.GetString(assetData); + + // data = ProcessAssetDataString(data); + + // return Encoding.ASCII.GetBytes(data); + // } + + public string ProcessAssetDataString(string data) + { + Regex regex = new Regex("(creator_id|owner_id)\\s+(\\S+)"); + + // IUserService userService = null; + + data = regex.Replace(data, delegate(Match m) + { + string result = String.Empty; + +// string key = m.Groups[1].Captures[0].Value; +// +// string value = m.Groups[2].Captures[0].Value; +// +// Guid userUri; +// +// switch (key) +// { +// case "creator_id": +// userUri = new Guid(value); +// // result = "creator_url " + userService(userService, userUri); +// break; +// +// case "owner_id": +// userUri = new Guid(value); +// // result = "owner_url " + ResolveUserUri(userService, userUri); +// break; +// } + + return result; + }); + + return data; + } + + private string SLAssetTypeToContentType(int assetType) + { + switch (assetType) + { + case 0: + return "image/jp2"; + case 1: + return "application/ogg"; + case 2: + return "application/x-metaverse-callingcard"; + case 3: + return "application/x-metaverse-landmark"; + case 5: + return "application/x-metaverse-clothing"; + case 6: + return "application/x-metaverse-primitive"; + case 7: + return "application/x-metaverse-notecard"; + case 8: + return "application/x-metaverse-folder"; + case 10: + return "application/x-metaverse-lsl"; + case 11: + return "application/x-metaverse-lso"; + case 12: + return "image/tga"; + case 13: + return "application/x-metaverse-bodypart"; + case 17: + return "audio/x-wav"; + case 19: + return "image/jpeg"; + case 20: + return "application/x-metaverse-animation"; + case 21: + return "application/x-metaverse-gesture"; + case 22: + return "application/x-metaverse-simstate"; + default: + return "application/octet-stream"; + } + } + } +} diff --git a/OpenSim/Framework/Servers/CheckSumServer.cs b/OpenSim/Framework/Servers/CheckSumServer.cs new file mode 100644 index 0000000000..63059f0afc --- /dev/null +++ b/OpenSim/Framework/Servers/CheckSumServer.cs @@ -0,0 +1,26 @@ +/* + * 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. + */ diff --git a/OpenSim/Framework/Servers/GetAssetStreamHandler.cs b/OpenSim/Framework/Servers/GetAssetStreamHandler.cs new file mode 100644 index 0000000000..c935d2a579 --- /dev/null +++ b/OpenSim/Framework/Servers/GetAssetStreamHandler.cs @@ -0,0 +1,217 @@ +/* + * 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 OpenSimulator 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.IO; +using System.Reflection; +using System.Text; +using System.Text.RegularExpressions; +using System.Xml; +using System.Xml.Serialization; +using log4net; +using OpenMetaverse; +using OpenSim.Data; +using OpenSim.Framework; +using OpenSim.Framework.Servers; +using OpenSim.Framework.Servers.HttpServer; +using OpenSim.Framework.Statistics; +using System.Net; + +namespace OpenSim.Framework.Servers +{ + public class GetAssetStreamHandler : BaseStreamHandler + { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + // private OpenAsset_Main m_assetManager; + private IAssetDataPlugin m_assetProvider; + + /// + /// Constructor. + /// + /// + /// + public GetAssetStreamHandler(IAssetDataPlugin assetProvider) + : base("GET", "/assets") + { + m_log.Info("[REST]: In Get Request"); + // m_assetManager = assetManager; + m_assetProvider = assetProvider; + } + + public override byte[] Handle(string path, Stream request, + OSHttpRequest httpRequest, OSHttpResponse httpResponse) + { + string param = GetParam(path); + byte[] result = new byte[] { }; + + string[] p = param.Split(new char[] { '/', '?', '&' }, StringSplitOptions.RemoveEmptyEntries); + + if (p.Length > 0) + { + UUID assetID = UUID.Zero; + + if (!UUID.TryParse(p[0], out assetID)) + { + m_log.InfoFormat( + "[REST]: GET:/asset ignoring request with malformed UUID {0}", p[0]); + return result; + } + + if (StatsManager.AssetStats != null) + StatsManager.AssetStats.AddRequest(); + + AssetBase asset = m_assetProvider.FetchAsset(assetID); + if (asset != null) + { +// if (asset.ContainsReferences) +// { +// asset.Data = ProcessOutgoingAssetData(asset.Data); +// } + if (p.Length > 1 && p[1] == "data") + { + httpResponse.StatusCode = (int)HttpStatusCode.OK; + httpResponse.ContentType = SLAssetTypeToContentType(asset.Type); + result = asset.Data; + } + else + { + XmlSerializer xs = new XmlSerializer(typeof(AssetBase)); + MemoryStream ms = new MemoryStream(); + XmlTextWriter xw = new XmlTextWriter(ms, Encoding.UTF8); + xw.Formatting = Formatting.Indented; + xs.Serialize(xw, asset); + xw.Flush(); + + ms.Seek(0, SeekOrigin.Begin); + //StreamReader sr = new StreamReader(ms); + + result = ms.GetBuffer(); + + Array.Resize(ref result, (int)ms.Length); + } + } + else + { + if (StatsManager.AssetStats != null) + StatsManager.AssetStats.AddNotFoundRequest(); + + m_log.InfoFormat("[REST]: GET:/asset failed to find {0}", assetID); + } + } + + return result; + } + + // private byte[] ProcessOutgoingAssetData(byte[] assetData) + // { + // string data = Encoding.ASCII.GetString(assetData); + + // data = ProcessAssetDataString(data); + + // return Encoding.ASCII.GetBytes(data); + // } + + public string ProcessAssetDataString(string data) + { + Regex regex = new Regex("(creator_id|owner_id)\\s+(\\S+)"); + + // IUserService userService = null; + + data = regex.Replace(data, delegate(Match m) + { + string result = String.Empty; + +// string key = m.Groups[1].Captures[0].Value; +// +// string value = m.Groups[2].Captures[0].Value; +// +// Guid userUri; +// +// switch (key) +// { +// case "creator_id": +// userUri = new Guid(value); +// // result = "creator_url " + userService(userService, userUri); +// break; +// +// case "owner_id": +// userUri = new Guid(value); +// // result = "owner_url " + ResolveUserUri(userService, userUri); +// break; +// } + + return result; + }); + + return data; + } + + private string SLAssetTypeToContentType(int assetType) + { + switch (assetType) + { + case 0: + return "image/jp2"; + case 1: + return "application/ogg"; + case 2: + return "application/x-metaverse-callingcard"; + case 3: + return "application/x-metaverse-landmark"; + case 5: + return "application/x-metaverse-clothing"; + case 6: + return "application/x-metaverse-primitive"; + case 7: + return "application/x-metaverse-notecard"; + case 8: + return "application/x-metaverse-folder"; + case 10: + return "application/x-metaverse-lsl"; + case 11: + return "application/x-metaverse-lso"; + case 12: + return "image/tga"; + case 13: + return "application/x-metaverse-bodypart"; + case 17: + return "audio/x-wav"; + case 19: + return "image/jpeg"; + case 20: + return "application/x-metaverse-animation"; + case 21: + return "application/x-metaverse-gesture"; + case 22: + return "application/x-metaverse-simstate"; + default: + return "application/octet-stream"; + } + } + } +} diff --git a/OpenSim/Framework/Servers/HttpServer/BaseHTTPHandler.cs b/OpenSim/Framework/Servers/HttpServer/BaseHTTPHandler.cs new file mode 100644 index 0000000000..fc89e3059f --- /dev/null +++ b/OpenSim/Framework/Servers/HttpServer/BaseHTTPHandler.cs @@ -0,0 +1,41 @@ +/* + * 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.Collections; + +namespace OpenSim.Framework.Servers.HttpServer +{ + public abstract class BaseHTTPHandler : BaseRequestHandler, IGenericHTTPHandler + { + public abstract Hashtable Handle(string path, Hashtable Request); + + protected BaseHTTPHandler(string httpMethod, string path) + : base(httpMethod, path) + { + } + } +} diff --git a/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs b/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs new file mode 100644 index 0000000000..779f577ae2 --- /dev/null +++ b/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs @@ -0,0 +1,1626 @@ +/* + * 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.Collections; +using System.Collections.Generic; +using System.IO; +using System.Net; +using System.Net.Sockets; +using System.Reflection; +using System.Globalization; +using System.Text; +using System.Threading; +using System.Xml; +using HttpServer; +using log4net; +using Nwc.XmlRpc; +using OpenMetaverse.StructuredData; +using CoolHTTPListener = HttpServer.HttpListener; +using HttpListener=System.Net.HttpListener; + +namespace OpenSim.Framework.Servers.HttpServer +{ + public class BaseHttpServer : IHttpServer + { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + private HttpServerLogWriter httpserverlog = new HttpServerLogWriter(); + + private volatile int NotSocketErrors = 0; + public volatile bool HTTPDRunning = false; + + protected Thread m_workerThread; + // protected HttpListener m_httpListener; + protected CoolHTTPListener m_httpListener2; + protected Dictionary m_rpcHandlers = new Dictionary(); + protected Dictionary m_rpcHandlersKeepAlive = new Dictionary(); + protected DefaultLLSDMethod m_defaultLlsdHandler = null; // <-- Moving away from the monolithic.. and going to /registered/ + protected Dictionary m_llsdHandlers = new Dictionary(); + protected Dictionary m_streamHandlers = new Dictionary(); + protected Dictionary m_HTTPHandlers = new Dictionary(); + protected Dictionary m_agentHandlers = new Dictionary(); + + protected uint m_port; + protected uint m_sslport; + protected bool m_ssl; + protected bool m_firstcaps = true; + protected string m_SSLCommonName = ""; + + public uint SSLPort + { + get { return m_sslport; } + } + + public string SSLCommonName + { + get { return m_SSLCommonName; } + } + + public uint Port + { + get { return m_port; } + } + + public bool UseSSL + { + get { return m_ssl; } + } + + public BaseHttpServer(uint port) + { + m_port = port; + } + + public BaseHttpServer(uint port, bool ssl) : this (port) + { + m_ssl = ssl; + } + + public BaseHttpServer(uint port, bool ssl, uint sslport, string CN) : this (port, ssl) + { + if (m_ssl) + { + m_sslport = sslport; + } + } + + /// + /// Add a stream handler to the http server. If the handler already exists, then nothing happens. + /// + /// + public void AddStreamHandler(IRequestHandler handler) + { + string httpMethod = handler.HttpMethod; + string path = handler.Path; + string handlerKey = GetHandlerKey(httpMethod, path); + + lock (m_streamHandlers) + { + if (!m_streamHandlers.ContainsKey(handlerKey)) + { + // m_log.DebugFormat("[BASE HTTP SERVER]: Adding handler key {0}", handlerKey); + m_streamHandlers.Add(handlerKey, handler); + } + } + } + + private static string GetHandlerKey(string httpMethod, string path) + { + return httpMethod + ":" + path; + } + + public bool AddXmlRPCHandler(string method, XmlRpcMethod handler) + { + return AddXmlRPCHandler(method, handler, true); + } + + public bool AddXmlRPCHandler(string method, XmlRpcMethod handler, bool keepAlive) + { + lock (m_rpcHandlers) + { + m_rpcHandlers[method] = handler; + m_rpcHandlersKeepAlive[method] = keepAlive; // default + } + + return true; + } + + public XmlRpcMethod GetXmlRPCHandler(string method) + { + lock (m_rpcHandlers) + { + if (m_rpcHandlers.ContainsKey(method)) + { + return m_rpcHandlers[method]; + } + else + { + return null; + } + } + } + + public bool AddHTTPHandler(string methodName, GenericHTTPMethod handler) + { + //m_log.DebugFormat("[BASE HTTP SERVER]: Registering {0}", methodName); + + lock (m_HTTPHandlers) + { + if (!m_HTTPHandlers.ContainsKey(methodName)) + { + m_HTTPHandlers.Add(methodName, handler); + return true; + } + } + + //must already have a handler for that path so return false + 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) + { + lock (m_agentHandlers) + { + if (!m_agentHandlers.ContainsKey(agent)) + { + m_agentHandlers.Add(agent, handler); + return true; + } + } + + //must already have a handler for that path so return false + return false; + } + + public bool AddLLSDHandler(string path, LLSDMethod handler) + { + lock (m_llsdHandlers) + { + if (!m_llsdHandlers.ContainsKey(path)) + { + m_llsdHandlers.Add(path, handler); + return true; + } + } + return false; + } + + public bool SetDefaultLLSDHandler(DefaultLLSDMethod handler) + { + m_defaultLlsdHandler = handler; + return true; + } + + public void OnHandleRequestIOThread(IHttpClientContext context, IHttpRequest request) + { + OSHttpRequest req = new OSHttpRequest(context, request); + OSHttpResponse resp = new OSHttpResponse(new HttpResponse(context, request)); + //resp.KeepAlive = req.KeepAlive; + //m_log.Info("[Debug BASE HTTP SERVER]: Got Request"); + //HttpServerContextObj objstate= new HttpServerContextObj(req,resp); + //ThreadPool.QueueUserWorkItem(new WaitCallback(ConvertIHttpClientContextToOSHttp), (object)objstate); + HandleRequest(req, resp); + } + + public void ConvertIHttpClientContextToOSHttp(object stateinfo) + { + HttpServerContextObj objstate = (HttpServerContextObj)stateinfo; + //OSHttpRequest request = new OSHttpRequest(objstate.context,objstate.req); + //OSHttpResponse resp = new OSHttpResponse(new HttpServer.HttpResponse(objstate.context, objstate.req)); + + OSHttpRequest request = objstate.oreq; + OSHttpResponse resp = objstate.oresp; + //OSHttpResponse resp = new OSHttpResponse(new HttpServer.HttpResponse(objstate.context, objstate.req)); + + /* + request.AcceptTypes = objstate.req.AcceptTypes; + request.ContentLength = (long)objstate.req.ContentLength; + request.Headers = objstate.req.Headers; + request.HttpMethod = objstate.req.Method; + request.InputStream = objstate.req.Body; + foreach (string str in request.Headers) + { + if (str.ToLower().Contains("content-type: ")) + { + request.ContentType = str.Substring(13, str.Length - 13); + break; + } + } + //request.KeepAlive = objstate.req. + foreach (HttpServer.HttpInput httpinput in objstate.req.QueryString) + { + request.QueryString.Add(httpinput.Name, httpinput[httpinput.Name]); + } + + //request.Query = objstate.req.//objstate.req.QueryString; + //foreach ( + //request.QueryString = objstate.req.QueryString; + + */ + HandleRequest(request,resp); + } + + public virtual void HandleRequest(OSHttpRequest request, OSHttpResponse response) + { + try + { + Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US", true); + // This is the REST agent interface. We require an agent to properly identify + // itself. If the REST handler recognizes the prefix it will attempt to + // satisfy the request. If it is not recognizable, and no damage has occurred + // the request can be passed through to the other handlers. This is a low + // probability event; if a request is matched it is normally expected to be + // handled + //m_log.Debug("[BASE HTTP SERVER]: Handling Request" + request.RawUrl); + IHttpAgentHandler agentHandler; + + if (TryGetAgentHandler(request, response, out agentHandler)) + { + if (HandleAgentRequest(agentHandler, request, response)) + { + return; + } + } + + IRequestHandler requestHandler; + //response.KeepAlive = true; + response.SendChunked = false; + + string path = request.RawUrl; + string handlerKey = GetHandlerKey(request.HttpMethod, path); + + //m_log.DebugFormat("[BASE HTTP SERVER]: Handling {0} request for {1}", request.HttpMethod, path); + + if (TryGetStreamHandler(handlerKey, out requestHandler)) + { + //m_log.Debug("[BASE HTTP SERVER]: Found Stream Handler"); + // Okay, so this is bad, but should be considered temporary until everything is IStreamHandler. + byte[] buffer; + + response.ContentType = requestHandler.ContentType; // Lets do this defaulting before in case handler has varying content type. + + if (requestHandler is IStreamedRequestHandler) + { + IStreamedRequestHandler streamedRequestHandler = requestHandler as IStreamedRequestHandler; + + buffer = streamedRequestHandler.Handle(path, request.InputStream, request, response); + } + else if (requestHandler is IGenericHTTPHandler) + { + //m_log.Debug("[BASE HTTP SERVER]: Found Caps based HTTP Handler"); + IGenericHTTPHandler HTTPRequestHandler = requestHandler as IGenericHTTPHandler; + Stream requestStream = request.InputStream; + + Encoding encoding = Encoding.UTF8; + StreamReader reader = new StreamReader(requestStream, encoding); + + string requestBody = reader.ReadToEnd(); + + reader.Close(); + requestStream.Close(); + + Hashtable keysvals = new Hashtable(); + Hashtable headervals = new Hashtable(); + //string host = String.Empty; + + string[] querystringkeys = request.QueryString.AllKeys; + string[] rHeaders = request.Headers.AllKeys; + + + foreach (string queryname in querystringkeys) + { + keysvals.Add(queryname, request.QueryString[queryname]); + } + + foreach (string headername in rHeaders) + { + //m_log.Warn("[HEADER]: " + headername + "=" + request.Headers[headername]); + headervals[headername] = request.Headers[headername]; + } + + // if (headervals.Contains("Host")) + // { + // host = (string)headervals["Host"]; + // } + + keysvals.Add("requestbody", requestBody); + if (keysvals.Contains("method")) + { + //m_log.Warn("[HTTP]: Contains Method"); + //string method = (string)keysvals["method"]; + //m_log.Warn("[HTTP]: " + requestBody); + + } + DoHTTPGruntWork(HTTPRequestHandler.Handle(path, keysvals), response); + return; + } + else + { + IStreamHandler streamHandler = (IStreamHandler)requestHandler; + + using (MemoryStream memoryStream = new MemoryStream()) + { + streamHandler.Handle(path, request.InputStream, memoryStream, request, response); + memoryStream.Flush(); + buffer = memoryStream.ToArray(); + } + } + + request.InputStream.Close(); + + if (!response.SendChunked) + response.ContentLength64 = buffer.LongLength; + + try + { + response.OutputStream.Write(buffer, 0, buffer.Length); + //response.OutputStream.Close(); + } + catch (HttpListenerException) + { + m_log.WarnFormat("[BASE HTTP SERVER]: HTTP request abnormally terminated."); + } + //response.OutputStream.Close(); + try + { + response.Send(); + } + catch (SocketException e) + { + // This has to be here to prevent a Linux/Mono crash + m_log.WarnFormat("[BASE HTTP SERVER] XmlRpcRequest issue {0}.\nNOTE: this may be spurious on Linux.", e); + } + return; + } + + if (request.AcceptTypes != null && request.AcceptTypes.Length > 0) + { + foreach (string strAccept in request.AcceptTypes) + { + if (strAccept.Contains("application/llsd+xml")) + { + //m_log.Info("[Debug BASE HTTP SERVER]: Found an application/llsd+xml accept header"); + HandleLLSDRequests(request, response); + return; + } + } + } + + switch (request.ContentType) + { + case null: + case "text/html": + //m_log.Info("[Debug BASE HTTP SERVER]: found a text/html content type"); + HandleHTTPRequest(request, response); + return; + + case "application/llsd+xml": + case "application/xml+llsd": + //m_log.Info("[Debug BASE HTTP SERVER]: found a application/llsd+xml content type"); + HandleLLSDRequests(request, response); + return; + + case "text/xml": + case "application/xml": + default: + //m_log.Info("[Debug BASE HTTP SERVER]: in default handler"); + // Point of note.. the DoWeHaveA methods check for an EXACT path + // if (request.RawUrl.Contains("/CAPS/EQG")) + // { + // int i = 1; + // } + //m_log.Info("[Debug BASE HTTP SERVER]: Checking for LLSD Handler"); + if (DoWeHaveALLSDHandler(request.RawUrl)) + { + //m_log.Info("[Debug BASE HTTP SERVER]: Found LLSD Handler"); + HandleLLSDRequests(request, response); + return; + } + //m_log.Info("[Debug BASE HTTP SERVER]: Checking for HTTP Handler"); + if (DoWeHaveAHTTPHandler(request.RawUrl)) + { + //m_log.Info("[Debug BASE HTTP SERVER]: found HTTP Handler"); + HandleHTTPRequest(request, response); + return; + } + + //m_log.Info("[Debug BASE HTTP SERVER]: Generic XMLRPC"); + // generic login request. + HandleXmlRpcRequests(request, response); + + return; + } + } + catch (SocketException e) + { + // At least on linux, it appears that if the client makes a request without requiring the response, + // an unconnected socket exception is thrown when we close the response output stream. There's no + // obvious way to tell if the client didn't require the response, so instead we'll catch and ignore + // the exception instead. + // + // An alternative may be to turn off all response write exceptions on the HttpListener, but let's go + // with the minimum first + m_log.WarnFormat("[BASE HTTP SERVER]: HandleRequest threw {0}.\nNOTE: this may be spurious on Linux", e); + } + catch (EndOfStreamException e) + { + m_log.ErrorFormat("[BASE HTTP SERVER]: HandleRequest() threw {0}", e); + } + catch (InvalidOperationException e) + { + m_log.ErrorFormat("[BASE HTTP SERVER]: HandleRequest() threw {0}", e); + SendHTML500(response); + } + } + + private bool TryGetStreamHandler(string handlerKey, out IRequestHandler streamHandler) + { + string bestMatch = null; + + lock (m_streamHandlers) + { + foreach (string pattern in m_streamHandlers.Keys) + { + if (handlerKey.StartsWith(pattern)) + { + if (String.IsNullOrEmpty(bestMatch) || pattern.Length > bestMatch.Length) + { + bestMatch = pattern; + } + } + } + + if (String.IsNullOrEmpty(bestMatch)) + { + streamHandler = null; + return false; + } + else + { + streamHandler = m_streamHandlers[bestMatch]; + return true; + } + } + } + + private bool TryGetHTTPHandler(string handlerKey, out GenericHTTPMethod HTTPHandler) + { + //m_log.DebugFormat("[BASE HTTP HANDLER]: Looking for HTTP handler for {0}", handlerKey); + + string bestMatch = null; + + lock (m_HTTPHandlers) + { + foreach (string pattern in m_HTTPHandlers.Keys) + { + if (handlerKey.StartsWith(pattern)) + { + if (String.IsNullOrEmpty(bestMatch) || pattern.Length > bestMatch.Length) + { + bestMatch = pattern; + } + } + } + + if (String.IsNullOrEmpty(bestMatch)) + { + HTTPHandler = null; + return false; + } + else + { + HTTPHandler = m_HTTPHandlers[bestMatch]; + return true; + } + } + } + + private bool TryGetAgentHandler(OSHttpRequest request, OSHttpResponse response, out IHttpAgentHandler agentHandler) + { + agentHandler = null; + try + { + foreach (IHttpAgentHandler handler in m_agentHandlers.Values) + { + if (handler.Match(request, response)) + { + agentHandler = handler; + return true; + } + } + } + catch(KeyNotFoundException) + { + } + + return false; + } + + /// + /// Try all the registered xmlrpc handlers when an xmlrpc request is received. + /// Sends back an XMLRPC unknown request response if no handler is registered for the requested method. + /// + /// + /// + private void HandleXmlRpcRequests(OSHttpRequest request, OSHttpResponse response) + { + Stream requestStream = request.InputStream; + + Encoding encoding = Encoding.UTF8; + StreamReader reader = new StreamReader(requestStream, encoding); + + string requestBody = reader.ReadToEnd(); + reader.Close(); + requestStream.Close(); + + string responseString = String.Empty; + XmlRpcRequest xmlRprcRequest = null; + + try + { + xmlRprcRequest = (XmlRpcRequest) (new XmlRpcRequestDeserializer()).Deserialize(requestBody); + } + catch (XmlException) + { + } + + if (xmlRprcRequest != null) + { + string methodName = xmlRprcRequest.MethodName; + if (methodName != null) + { + xmlRprcRequest.Params.Add(request.RemoteIPEndPoint); // Param[1] + XmlRpcResponse xmlRpcResponse; + + XmlRpcMethod method; + bool methodWasFound; + lock (m_rpcHandlers) + { + methodWasFound = m_rpcHandlers.TryGetValue(methodName, out method); + } + + if (methodWasFound) + { + xmlRprcRequest.Params.Add(request.Url); // Param[2] + + try + { + xmlRpcResponse = method(xmlRprcRequest); + } + catch(Exception e) + { + // if the registered XmlRpc method threw an exception, we pass a fault-code along + xmlRpcResponse = new XmlRpcResponse(); + // Code probably set in accordance with http://xmlrpc-epi.sourceforge.net/specs/rfc.fault_codes.php + xmlRpcResponse.SetFault(-32603, String.Format("Requested method [{0}] threw exception: {1}", + methodName, e.Message)); + } + // if the method wasn't found, we can't determine KeepAlive state anyway, so lets do it only here + response.KeepAlive = m_rpcHandlersKeepAlive[methodName]; + } + else + { + xmlRpcResponse = new XmlRpcResponse(); + // Code set in accordance with http://xmlrpc-epi.sourceforge.net/specs/rfc.fault_codes.php + xmlRpcResponse.SetFault(-32601, String.Format("Requested method [{0}] not found", methodName)); + } + + responseString = XmlRpcResponseSerializer.Singleton.Serialize(xmlRpcResponse); + } + else + { + //HandleLLSDRequests(request, response); + response.ContentType = "text/plain"; + response.StatusCode = 404; + response.StatusDescription = "Not Found"; + response.ProtocolVersion = "HTTP/1.0"; + byte[] buf = Encoding.UTF8.GetBytes("Not found"); + response.KeepAlive = false; + + m_log.ErrorFormat("[BASE HTTP SERVER] Handler not found for http request {0}", request.RawUrl); + + response.SendChunked = false; + response.ContentLength64 = buf.Length; + response.ContentEncoding = Encoding.UTF8; + try + { + response.OutputStream.Write(buf, 0, buf.Length); + } + catch (Exception ex) + { + m_log.Warn("[HTTPD]: Error - " + ex.Message); + } + finally + { + try + { + response.Send(); + } + catch (SocketException e) + { + // This has to be here to prevent a Linux/Mono crash + m_log.WarnFormat("[BASE HTTP SERVER] XmlRpcRequest issue {0}.\nNOTE: this may be spurious on Linux.", e); + } + } + return; + //responseString = "Error"; + } + } + + response.ContentType = "text/xml"; + + byte[] buffer = Encoding.UTF8.GetBytes(responseString); + + response.SendChunked = false; + response.ContentLength64 = buffer.Length; + response.ContentEncoding = Encoding.UTF8; + try + { + response.OutputStream.Write(buffer, 0, buffer.Length); + } + catch (Exception ex) + { + m_log.Warn("[HTTPD]: Error - " + ex.Message); + } + finally + { + try + { + response.Send(); + } + catch (SocketException e) + { + // This has to be here to prevent a Linux/Mono crash + m_log.WarnFormat("[BASE HTTP SERVER] XmlRpcRequest issue {0}.\nNOTE: this may be spurious on Linux.", e); + } + } + } + + private void HandleLLSDRequests(OSHttpRequest request, OSHttpResponse response) + { + //m_log.Warn("[BASE HTTP SERVER]: We've figured out it's a LLSD Request"); + Stream requestStream = request.InputStream; + + Encoding encoding = Encoding.UTF8; + StreamReader reader = new StreamReader(requestStream, encoding); + + string requestBody = reader.ReadToEnd(); + reader.Close(); + requestStream.Close(); + + //m_log.DebugFormat("[OGP]: {0}:{1}", request.RawUrl, requestBody); + response.KeepAlive = true; + + OSD llsdRequest = null; + OSD llsdResponse = null; + + bool LegacyLLSDLoginLibOMV = (requestBody.Contains("passwd") && requestBody.Contains("mac") && requestBody.Contains("viewer_digest")); + + if (requestBody.Length == 0) + // Get Request + { + requestBody = "requestget"; + } + try + { + llsdRequest = OSDParser.DeserializeLLSDXml(requestBody); + } + catch (Exception ex) + { + m_log.Warn("[HTTPD]: Error - " + ex.Message); + } + + if (llsdRequest != null)// && m_defaultLlsdHandler != null) + { + + LLSDMethod llsdhandler = null; + + if (TryGetLLSDHandler(request.RawUrl, out llsdhandler) && !LegacyLLSDLoginLibOMV) + { + // we found a registered llsd handler to service this request + llsdResponse = llsdhandler(request.RawUrl, llsdRequest, request.RemoteIPEndPoint.ToString()); + } + else + { + // we didn't find a registered llsd handler to service this request + // check if we have a default llsd handler + + if (m_defaultLlsdHandler != null) + { + // LibOMV path + llsdResponse = m_defaultLlsdHandler(llsdRequest); + } + else + { + // Oops, no handler for this.. give em the failed message + llsdResponse = GenerateNoLLSDHandlerResponse(); + } + } + + } + else + { + llsdResponse = GenerateNoLLSDHandlerResponse(); + } + byte[] buffer = new byte[0]; + if (llsdResponse.ToString() == "shutdown404!") + { + response.ContentType = "text/plain"; + response.StatusCode = 404; + response.StatusDescription = "Not Found"; + response.ProtocolVersion = "HTTP/1.0"; + buffer = Encoding.UTF8.GetBytes("Not found"); + } + else + { + response.ContentType = "application/llsd+xml"; + //m_log.Info("[Debug BASE HTTP SERVER]: Response: " + llsdResponse.ToString()); + buffer = OSDParser.SerializeLLSDXmlBytes(llsdResponse); + } + response.SendChunked = false; + response.ContentLength64 = buffer.Length; + response.ContentEncoding = Encoding.UTF8; + response.KeepAlive = true; + + try + { + response.OutputStream.Write(buffer, 0, buffer.Length); + } + catch (Exception ex) + { + m_log.Warn("[HTTPD]: Error - " + ex.Message); + } + finally + { + //response.OutputStream.Close(); + try + { + response.Send(); + response.OutputStream.Flush(); + response.OutputStream.Close(); + } + catch (IOException e) + { + m_log.DebugFormat("[BASE HTTP SERVER] LLSD IOException {0}.", e); + } + catch (SocketException e) + { + // This has to be here to prevent a Linux/Mono crash + m_log.WarnFormat("[BASE HTTP SERVER] LLSD issue {0}.\nNOTE: this may be spurious on Linux.", e); + } + } + } + + /// + /// Checks if we have an Exact path in the LLSD handlers for the path provided + /// + /// URI of the request + /// true if we have one, false if not + private bool DoWeHaveALLSDHandler(string path) + { + + string[] pathbase = path.Split('/'); + string searchquery = "/"; + + if (pathbase.Length < 1) + return false; + + for (int i = 1; i < pathbase.Length; i++) + { + searchquery += pathbase[i]; + if (pathbase.Length - 1 != i) + searchquery += "/"; + } + + string bestMatch = null; + + foreach (string pattern in m_llsdHandlers.Keys) + { + + if (searchquery.StartsWith(pattern) && searchquery.Length >= pattern.Length) + { + + bestMatch = pattern; + + } + } + + // extra kicker to remove the default XMLRPC login case.. just in case.. + if (path != "/" && bestMatch == "/" && searchquery != "/") + return false; + + if (path == "/") + return false; + + if (String.IsNullOrEmpty(bestMatch)) + { + + return false; + } + else + { + + return true; + } + } + + /// + /// Checks if we have an Exact path in the HTTP handlers for the path provided + /// + /// URI of the request + /// true if we have one, false if not + private bool DoWeHaveAHTTPHandler(string path) + { + string[] pathbase = path.Split('/'); + string searchquery = "/"; + + if (pathbase.Length < 1) + return false; + + for (int i = 1; i < pathbase.Length; i++) + { + searchquery += pathbase[i]; + if (pathbase.Length - 1 != i) + searchquery += "/"; + } + + string bestMatch = null; + + //m_log.DebugFormat("[BASE HTTP HANDLER]: Checking if we have an HTTP handler for {0}", searchquery); + + lock (m_HTTPHandlers) + { + foreach (string pattern in m_HTTPHandlers.Keys) + { + if (searchquery.StartsWith(pattern) && searchquery.Length >= pattern.Length) + { + bestMatch = pattern; + } + } + + // extra kicker to remove the default XMLRPC login case.. just in case.. + if (path == "/") + return false; + + if (String.IsNullOrEmpty(bestMatch)) + { + return false; + } + else + { + return true; + } + } + } + + private bool TryGetLLSDHandler(string path, out LLSDMethod llsdHandler) + { + llsdHandler = null; + // Pull out the first part of the path + // splitting the path by '/' means we'll get the following return.. + // {0}/{1}/{2} + // where {0} isn't something we really control 100% + + string[] pathbase = path.Split('/'); + string searchquery = "/"; + + if (pathbase.Length < 1) + return false; + + for (int i=1; i bestMatch.Length) + { + // You have to specifically register for '/' and to get it, you must specificaly request it + // + if (pattern == "/" && searchquery == "/" || pattern != "/") + bestMatch = pattern; + } + } + } + + if (String.IsNullOrEmpty(bestMatch)) + { + llsdHandler = null; + return false; + } + else + { + llsdHandler = m_llsdHandlers[bestMatch]; + return true; + } + } + + private OSDMap GenerateNoLLSDHandlerResponse() + { + OSDMap map = new OSDMap(); + map["reason"] = OSD.FromString("LLSDRequest"); + map["message"] = OSD.FromString("No handler registered for LLSD Requests"); + map["login"] = OSD.FromString("false"); + return map; + } + /// + /// A specific agent handler was provided. Such a handler is expecetd to have an + /// intimate, and highly specific relationship with the client. Consequently, + /// nothing is done here. + /// + /// + /// + /// + + private bool HandleAgentRequest(IHttpAgentHandler handler, OSHttpRequest request, OSHttpResponse response) + { + // In the case of REST, then handler is responsible for ALL aspects of + // the request/response handling. Nothing is done here, not even encoding. + + try + { + return handler.Handle(request, response); + } + catch (Exception e) + { + // 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 = true; + response.StatusCode = (int)OSHttpStatusCode.ServerErrorInternalError; + //response.OutputStream.Close(); + try + { + response.Send(); + } + catch (SocketException f) + { + // This has to be here to prevent a Linux/Mono crash + m_log.WarnFormat( + "[BASE HTTP SERVER]: XmlRpcRequest issue {0}.\nNOTE: this may be spurious on Linux.", f); + } + } + catch(Exception) + { + } + } + + // Indicate that the request has been "handled" + + return true; + + } + + public void HandleHTTPRequest(OSHttpRequest request, OSHttpResponse response) + { + switch (request.HttpMethod) + { + case "OPTIONS": + response.StatusCode = (int)OSHttpStatusCode.SuccessOk; + return; + + default: + HandleContentVerbs(request, response); + return; + } + } + + private void HandleContentVerbs(OSHttpRequest request, OSHttpResponse response) + { + // This is a test. There's a workable alternative.. as this way sucks. + // We'd like to put this into a text file parhaps that's easily editable. + // + // For this test to work, I used the following secondlife.exe parameters + // "C:\Program Files\SecondLifeWindLight\SecondLifeWindLight.exe" -settings settings_windlight.xml -channel "Second Life WindLight" -set SystemLanguage en-us -loginpage http://10.1.1.2:8002/?show_login_form=TRUE -loginuri http://10.1.1.2:8002 -user 10.1.1.2 + // + // Even after all that, there's still an error, but it's a start. + // + // I depend on show_login_form being in the secondlife.exe parameters to figure out + // to display the form, or process it. + // a better way would be nifty. + + Stream requestStream = request.InputStream; + + Encoding encoding = Encoding.UTF8; + StreamReader reader = new StreamReader(requestStream, encoding); + + string requestBody = reader.ReadToEnd(); + // avoid warning for now + reader.ReadToEnd(); + reader.Close(); + requestStream.Close(); + + Hashtable keysvals = new Hashtable(); + Hashtable headervals = new Hashtable(); + + Hashtable requestVars = new Hashtable(); + + string host = String.Empty; + + string[] querystringkeys = request.QueryString.AllKeys; + string[] rHeaders = request.Headers.AllKeys; + + keysvals.Add("body", requestBody); + keysvals.Add("uri", request.RawUrl); + keysvals.Add("content-type", request.ContentType); + keysvals.Add("http-method", request.HttpMethod); + + foreach (string queryname in querystringkeys) + { + keysvals.Add(queryname, request.QueryString[queryname]); + requestVars.Add(queryname, keysvals[queryname]); + } + + foreach (string headername in rHeaders) + { + //m_log.Warn("[HEADER]: " + headername + "=" + request.Headers[headername]); + headervals[headername] = request.Headers[headername]; + } + + if (headervals.Contains("Host")) + { + host = (string)headervals["Host"]; + } + + keysvals.Add("headers",headervals); + keysvals.Add("querystringkeys", querystringkeys); + keysvals.Add("requestvars", requestVars); + + if (keysvals.Contains("method")) + { + //m_log.Warn("[HTTP]: Contains Method"); + string method = (string) keysvals["method"]; + //m_log.Warn("[HTTP]: " + requestBody); + GenericHTTPMethod requestprocessor; + bool foundHandler = TryGetHTTPHandler(method, out requestprocessor); + if (foundHandler) + { + Hashtable responsedata1 = requestprocessor(keysvals); + DoHTTPGruntWork(responsedata1,response); + + //SendHTML500(response); + } + else + { + //m_log.Warn("[HTTP]: Handler Not Found"); + SendHTML404(response, host); + } + } + else + { + + GenericHTTPMethod requestprocessor; + bool foundHandler = TryGetHTTPHandlerPathBased(request.RawUrl, out requestprocessor); + if (foundHandler) + { + Hashtable responsedata2 = requestprocessor(keysvals); + DoHTTPGruntWork(responsedata2, response); + + //SendHTML500(response); + } + else + { + //m_log.Warn("[HTTP]: Handler Not Found"); + SendHTML404(response, host); + } + } + } + + private bool TryGetHTTPHandlerPathBased(string path, out GenericHTTPMethod httpHandler) + { + httpHandler = null; + // Pull out the first part of the path + // splitting the path by '/' means we'll get the following return.. + // {0}/{1}/{2} + // where {0} isn't something we really control 100% + + string[] pathbase = path.Split('/'); + string searchquery = "/"; + + if (pathbase.Length < 1) + return false; + + for (int i = 1; i < pathbase.Length; i++) + { + searchquery += pathbase[i]; + if (pathbase.Length - 1 != i) + searchquery += "/"; + } + + // while the matching algorithm below doesn't require it, we're expecting a query in the form + // + // [] = optional + // /resource/UUID/action[/action] + // + // now try to get the closest match to the reigstered path + // at least for OGP, registered path would probably only consist of the /resource/ + + string bestMatch = null; + +// m_log.DebugFormat( +// "[BASE HTTP HANDLER]: TryGetHTTPHandlerPathBased() looking for HTTP handler to match {0}", searchquery); + + lock (m_HTTPHandlers) + { + foreach (string pattern in m_HTTPHandlers.Keys) + { + if (searchquery.ToLower().StartsWith(pattern.ToLower())) + { + if (String.IsNullOrEmpty(bestMatch) || searchquery.Length > bestMatch.Length) + { + // You have to specifically register for '/' and to get it, you must specificaly request it + // + if (pattern == "/" && searchquery == "/" || pattern != "/") + bestMatch = pattern; + } + } + } + + if (String.IsNullOrEmpty(bestMatch)) + { + httpHandler = null; + return false; + } + else + { + if (bestMatch == "/" && searchquery != "/") + return false; + + httpHandler = m_HTTPHandlers[bestMatch]; + return true; + } + } + } + + private static void DoHTTPGruntWork(Hashtable responsedata, OSHttpResponse response) + { + //m_log.Info("[BASE HTTP SERVER]: Doing HTTP Grunt work with response"); + int responsecode = (int)responsedata["int_response_code"]; + string responseString = (string)responsedata["str_response_string"]; + string contentType = (string)responsedata["content_type"]; + + if (responsedata.ContainsKey("error_status_text")) + { + response.StatusDescription = (string)responsedata["error_status_text"]; + } + if (responsedata.ContainsKey("http_protocol_version")) + { + response.ProtocolVersion = (string)responsedata["http_protocol_version"]; + } + + if (responsedata.ContainsKey("keepalive")) + { + bool keepalive = (bool)responsedata["keepalive"]; + response.KeepAlive = keepalive; + + } + //Even though only one other part of the entire code uses HTTPHandlers, we shouldn't expect this + //and should check for NullReferenceExceptions + + if (string.IsNullOrEmpty(contentType)) + { + contentType = "text/html"; + } + + // The client ignores anything but 200 here for web login, so ensure that this is 200 for that + + response.StatusCode = responsecode; + + if (responsecode == (int)OSHttpStatusCode.RedirectMovedPermanently) + { + response.RedirectLocation = (string)responsedata["str_redirect_location"]; + response.StatusCode = responsecode; + } + + response.AddHeader("Content-Type", contentType); + + byte[] buffer; + + if (!(contentType.Contains("image") + || contentType.Contains("x-shockwave-flash") + || contentType.Contains("application/x-oar"))) + { + // Text + buffer = Encoding.UTF8.GetBytes(responseString); + } + else + { + // Binary! + buffer = Convert.FromBase64String(responseString); + } + + response.SendChunked = false; + response.ContentLength64 = buffer.Length; + response.ContentEncoding = Encoding.UTF8; + + try + { + response.OutputStream.Write(buffer, 0, buffer.Length); + } + catch (Exception ex) + { + m_log.Warn("[HTTPD]: Error - " + ex.Message); + } + finally + { + //response.OutputStream.Close(); + try + { + response.Send(); + } + catch (SocketException e) + { + // This has to be here to prevent a Linux/Mono crash + m_log.WarnFormat("[BASE HTTP SERVER] XmlRpcRequest issue {0}.\nNOTE: this may be spurious on Linux.", e); + } + } + } + + 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 = 404; + response.AddHeader("Content-type", "text/html"); + + string responseString = GetHTTP404(host); + byte[] buffer = Encoding.UTF8.GetBytes(responseString); + + response.SendChunked = false; + response.ContentLength64 = buffer.Length; + response.ContentEncoding = Encoding.UTF8; + + try + { + response.OutputStream.Write(buffer, 0, buffer.Length); + } + catch (Exception ex) + { + m_log.Warn("[HTTPD]: Error - " + ex.Message); + } + finally + { + //response.OutputStream.Close(); + try + { + response.Send(); + } + catch (SocketException e) + { + // This has to be here to prevent a Linux/Mono crash + m_log.WarnFormat("[BASE HTTP SERVER] XmlRpcRequest issue {0}.\nNOTE: this may be spurious on Linux.", e); + } + } + } + + public void SendHTML500(OSHttpResponse response) + { + // I know this statuscode is dumb, but the client doesn't respond to 404s and 500s + response.StatusCode = (int)OSHttpStatusCode.SuccessOk; + response.AddHeader("Content-type", "text/html"); + + string responseString = GetHTTP500(); + byte[] buffer = Encoding.UTF8.GetBytes(responseString); + + response.SendChunked = false; + response.ContentLength64 = buffer.Length; + response.ContentEncoding = Encoding.UTF8; + try + { + response.OutputStream.Write(buffer, 0, buffer.Length); + } + catch (Exception ex) + { + m_log.Warn("[HTTPD]: Error - " + ex.Message); + } + finally + { + //response.OutputStream.Close(); + try + { + response.Send(); + } + catch (SocketException e) + { + // This has to be here to prevent a Linux/Mono crash + m_log.WarnFormat("[BASE HTTP SERVER] XmlRpcRequest issue {0}.\nNOTE: this may be spurious on Linux.", e); + } + } + } + + public void Start() + { + m_log.Info("[HTTPD]: Starting up HTTP Server"); + + //m_workerThread = new Thread(new ThreadStart(StartHTTP)); + //m_workerThread.Name = "HttpThread"; + //m_workerThread.IsBackground = true; + //m_workerThread.Start(); + //ThreadTracker.Add(m_workerThread); + StartHTTP(); + } + + private void StartHTTP() + { + try + { + m_log.Info("[HTTPD]: Spawned main thread OK"); + //m_httpListener = new HttpListener(); + NotSocketErrors = 0; + if (!m_ssl) + { + //m_httpListener.Prefixes.Add("http://+:" + m_port + "/"); + //m_httpListener.Prefixes.Add("http://10.1.1.5:" + m_port + "/"); + m_httpListener2 = new CoolHTTPListener(IPAddress.Any, (int)m_port); + m_httpListener2.ExceptionThrown += httpServerException; + m_httpListener2.LogWriter = httpserverlog; + + // Uncomment this line in addition to those in HttpServerLogWriter + // if you want more detailed trace information from the HttpServer + //m_httpListener2.UseTraceLogs = true; + + m_httpListener2.DisconnectHandler = httpServerDisconnectMonitor; + } + else + { + //m_httpListener.Prefixes.Add("https://+:" + (m_sslport) + "/"); + //m_httpListener.Prefixes.Add("http://+:" + m_port + "/"); + } + + m_httpListener2.RequestHandler += OnHandleRequestIOThread; + //m_httpListener.Start(); + m_httpListener2.Start(64); + HTTPDRunning = true; + + //HttpListenerContext context; + //while (true) + //{ + // context = m_httpListener.GetContext(); + // ThreadPool.QueueUserWorkItem(new WaitCallback(HandleRequest), context); + // } + } + catch (Exception e) + { + m_log.Error("[HTTPD]: Error - " + e.Message); + m_log.Error("[HTTPD]: Tip: Do you have permission to listen on port " + m_port + ", " + m_sslport + "?"); + + // We want this exception to halt the entire server since in current configurations we aren't too + // useful without inbound HTTP. + throw e; + } + } + + public void httpServerDisconnectMonitor(IHttpClientContext source, SocketError err) + { + switch (err) + { + case SocketError.NotSocket: + NotSocketErrors++; + + break; + } + } + + public void httpServerException(object source, Exception exception) + { + m_log.ErrorFormat("[HTTPSERVER]: {0} had an exception {1}", source.ToString(), exception.ToString()); + /* + if (HTTPDRunning)// && NotSocketErrors > 5) + { + Stop(); + Thread.Sleep(200); + StartHTTP(); + m_log.Warn("[HTTPSERVER]: Died. Trying to kick....."); + } + */ + } + + public void Stop() + { + HTTPDRunning = false; + m_httpListener2.ExceptionThrown -= httpServerException; + m_httpListener2.DisconnectHandler = null; + + m_httpListener2.LogWriter = null; + m_httpListener2.RequestHandler -= OnHandleRequestIOThread; + + m_httpListener2.Stop(); + } + + public void RemoveStreamHandler(string httpMethod, string path) + { + string handlerKey = GetHandlerKey(httpMethod, path); + + //m_log.DebugFormat("[BASE HTTP SERVER]: Removing handler key {0}", handlerKey); + + lock (m_streamHandlers) m_streamHandlers.Remove(handlerKey); + } + + public void RemoveHTTPHandler(string httpMethod, string path) + { + lock (m_HTTPHandlers) + { + if (httpMethod != null && httpMethod.Length == 0) + { + m_HTTPHandlers.Remove(path); + return; + } + + m_HTTPHandlers.Remove(GetHandlerKey(httpMethod, path)); + } + } + + public bool RemoveAgentHandler(string agent, IHttpAgentHandler handler) + { + try + { + if (handler == m_agentHandlers[agent]) + { + m_agentHandlers.Remove(agent); + return true; + } + } + catch(KeyNotFoundException) + { + } + + return false; + } + + public bool RemoveLLSDHandler(string path, LLSDMethod handler) + { + try + { + if (handler == m_llsdHandlers[path]) + { + m_llsdHandlers.Remove(path); + return true; + } + } + catch (KeyNotFoundException) + { + // This is an exception to prevent crashing because of invalid code + } + + return false; + } + + public string GetHTTP404(string host) + { + string file = Path.Combine(".", "http_404.html"); + if (!File.Exists(file)) + return getDefaultHTTP404(host); + + StreamReader sr = File.OpenText(file); + string result = sr.ReadToEnd(); + sr.Close(); + return result; + } + + public string GetHTTP500() + { + string file = Path.Combine(".", "http_500.html"); + if (!File.Exists(file)) + return getDefaultHTTP500(); + + StreamReader sr = File.OpenText(file); + string result = sr.ReadToEnd(); + sr.Close(); + return result; + } + + // Fallback HTTP responses in case the HTTP error response files don't exist + private static string getDefaultHTTP404(string host) + { + return "404 Page not found

Ooops!

The page you requested has been obsconded with by knomes. Find hippos quick!

If you are trying to log-in, your link parameters should have: "-loginpage http://" + host + "/?method=login -loginuri http://" + host + "/" in your link

"; + } + + private static string getDefaultHTTP500() + { + return "500 Internal Server Error

Ooops!

The server you requested is overun by knomes! Find hippos quick!

"; + } + } + + public class HttpServerContextObj + { + public IHttpClientContext context = null; + public IHttpRequest req = null; + public OSHttpRequest oreq = null; + public OSHttpResponse oresp = null; + + public HttpServerContextObj(IHttpClientContext contxt, IHttpRequest reqs) + { + context = contxt; + req = reqs; + } + + public HttpServerContextObj(OSHttpRequest osreq, OSHttpResponse osresp) + { + oreq = osreq; + oresp = osresp; + } + } + + /// + /// Relays HttpServer log messages to our own logging mechanism. + /// + /// There is also a UseTraceLogs line in this file that can be uncommented for more detailed log information + public class HttpServerLogWriter : ILogWriter + { + //private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + public void Write(object source, LogPrio priority, string message) + { + /* + switch (priority) + { + case HttpServer.LogPrio.Debug: + m_log.DebugFormat("[{0}]: {1}", source.ToString(), message); + break; + case HttpServer.LogPrio.Error: + m_log.ErrorFormat("[{0}]: {1}", source.ToString(), message); + break; + case HttpServer.LogPrio.Info: + m_log.InfoFormat("[{0}]: {1}", source.ToString(), message); + break; + case HttpServer.LogPrio.Warning: + m_log.WarnFormat("[{0}]: {1}", source.ToString(), message); + break; + case HttpServer.LogPrio.Fatal: + m_log.ErrorFormat("[{0}]: FATAL! - {1}", source.ToString(), message); + break; + default: + break; + } + */ + + return; + } + } +} diff --git a/OpenSim/Framework/Servers/HttpServer/BaseRequestHandler.cs b/OpenSim/Framework/Servers/HttpServer/BaseRequestHandler.cs new file mode 100644 index 0000000000..9334972c31 --- /dev/null +++ b/OpenSim/Framework/Servers/HttpServer/BaseRequestHandler.cs @@ -0,0 +1,71 @@ +/* + * 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; + +namespace OpenSim.Framework.Servers.HttpServer +{ + public class BaseRequestHandler + { + public virtual string ContentType + { + get { return "application/xml"; } + } + + private readonly string m_httpMethod; + + public virtual string HttpMethod + { + get { return m_httpMethod; } + } + + private readonly string m_path; + + protected BaseRequestHandler(string httpMethod, string path) + { + m_httpMethod = httpMethod; + m_path = path; + } + + public virtual string Path + { + get { return m_path; } + } + + protected string GetParam(string path) + { + try + { + return path.Substring(m_path.Length); + } + catch (Exception) + { + return String.Empty; + } + } + } +} diff --git a/OpenSim/Framework/Servers/HttpServer/BaseStreamHandler.cs b/OpenSim/Framework/Servers/HttpServer/BaseStreamHandler.cs new file mode 100644 index 0000000000..734e3e4e8a --- /dev/null +++ b/OpenSim/Framework/Servers/HttpServer/BaseStreamHandler.cs @@ -0,0 +1,41 @@ +/* + * 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.IO; + +namespace OpenSim.Framework.Servers.HttpServer +{ + public abstract class BaseStreamHandler : BaseRequestHandler, IStreamedRequestHandler + { + public abstract byte[] Handle(string path, Stream request, + OSHttpRequest httpRequest, OSHttpResponse httpResponse); + + protected BaseStreamHandler(string httpMethod, string path) : base(httpMethod, path) + { + } + } +} diff --git a/OpenSim/Framework/Servers/HttpServer/BinaryStreamHandler.cs b/OpenSim/Framework/Servers/HttpServer/BinaryStreamHandler.cs new file mode 100644 index 0000000000..fe5bcbc75a --- /dev/null +++ b/OpenSim/Framework/Servers/HttpServer/BinaryStreamHandler.cs @@ -0,0 +1,73 @@ +/* + * 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.IO; +using System.Text; + +namespace OpenSim.Framework.Servers.HttpServer +{ + public delegate string BinaryMethod(byte[] data, string path, string param); + + public class BinaryStreamHandler : BaseStreamHandler + { + private BinaryMethod m_method; + + public override byte[] Handle(string path, Stream request, OSHttpRequest httpRequest, OSHttpResponse httpResponse) + { + byte[] data = ReadFully(request); + string param = GetParam(path); + string responseString = m_method(data, path, param); + + return Encoding.UTF8.GetBytes(responseString); + } + + public BinaryStreamHandler(string httpMethod, string path, BinaryMethod binaryMethod) + : base(httpMethod, path) + { + m_method = binaryMethod; + } + + private static byte[] ReadFully(Stream stream) + { + byte[] buffer = new byte[32768]; + using (MemoryStream ms = new MemoryStream()) + { + while (true) + { + int read = stream.Read(buffer, 0, buffer.Length); + + if (read <= 0) + { + return ms.ToArray(); + } + + ms.Write(buffer, 0, read); + } + } + } + } +} diff --git a/OpenSim/Framework/Servers/HttpServer/GenericHTTPMethod.cs b/OpenSim/Framework/Servers/HttpServer/GenericHTTPMethod.cs new file mode 100644 index 0000000000..060761aca6 --- /dev/null +++ b/OpenSim/Framework/Servers/HttpServer/GenericHTTPMethod.cs @@ -0,0 +1,33 @@ +/* + * 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.Collections; + +namespace OpenSim.Framework.Servers.HttpServer +{ + public delegate Hashtable GenericHTTPMethod(Hashtable request); +} diff --git a/OpenSim/Framework/Servers/HttpServer/Interfaces/IHttpAgentHandler.cs b/OpenSim/Framework/Servers/HttpServer/Interfaces/IHttpAgentHandler.cs new file mode 100644 index 0000000000..60c8e6ed00 --- /dev/null +++ b/OpenSim/Framework/Servers/HttpServer/Interfaces/IHttpAgentHandler.cs @@ -0,0 +1,35 @@ +/* + * 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.HttpServer +{ + public interface IHttpAgentHandler + { + bool Handle(OSHttpRequest req, OSHttpResponse resp); + bool Match(OSHttpRequest req, OSHttpResponse resp); + } +} diff --git a/OpenSim/Framework/Servers/HttpServer/Interfaces/IHttpServer.cs b/OpenSim/Framework/Servers/HttpServer/Interfaces/IHttpServer.cs new file mode 100644 index 0000000000..6e3cc49dc6 --- /dev/null +++ b/OpenSim/Framework/Servers/HttpServer/Interfaces/IHttpServer.cs @@ -0,0 +1,126 @@ +/* + * 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 Nwc.XmlRpc; + +namespace OpenSim.Framework.Servers.HttpServer +{ + /// + /// Interface to OpenSimulator's built in HTTP server. Use this to register handlers (http, llsd, xmlrpc, etc.) + /// for given URLs. + /// + public interface IHttpServer + { + uint SSLPort { get; } + string SSLCommonName { get; } + + uint Port { get; } + bool UseSSL { get; } + + // Note that the agent string is provided simply to differentiate + // the handlers - it is NOT required to be an actual agent header + // value. + bool AddAgentHandler(string agent, IHttpAgentHandler handler); + + /// + /// Add a handler for an HTTP request + /// + /// + /// This handler can actually be invoked either as + /// + /// http://:/?method= + /// + /// or + /// + /// http://: + /// + /// if the method name starts with a slash. For example, AddHTTPHandler("/object/", ...) on a standalone region + /// server will register a handler that can be invoked with either + /// + /// http://localhost:9000/?method=/object/ + /// + /// or + /// + /// http://localhost:9000/object/ + /// + /// + /// + /// + /// true if the handler was successfully registered, false if a handler with the same name already existed. + /// + bool AddHTTPHandler(string methodName, GenericHTTPMethod handler); + + /// + /// Adds a LLSD handler, yay. + /// + /// /resource/ path + /// handle the LLSD response + /// + bool AddLLSDHandler(string path, LLSDMethod handler); + + /// + /// Add a stream handler to the http server. If the handler already exists, then nothing happens. + /// + /// + void AddStreamHandler(IRequestHandler handler); + + bool AddXmlRPCHandler(string method, XmlRpcMethod handler); + bool AddXmlRPCHandler(string method, XmlRpcMethod handler, bool keepAlive); + + /// + /// Gets the XML RPC handler for given method name + /// + /// Name of the method + /// Returns null if not found + XmlRpcMethod GetXmlRPCHandler(string method); + + bool SetDefaultLLSDHandler(DefaultLLSDMethod handler); + + /// + /// Remove the agent if it is registered. + /// + /// + /// + /// + bool RemoveAgentHandler(string agent, IHttpAgentHandler handler); + + /// + /// Remove an HTTP handler + /// + /// + /// + void RemoveHTTPHandler(string httpMethod, string path); + + bool RemoveLLSDHandler(string path, LLSDMethod handler); + + void RemoveStreamHandler(string httpMethod, string path); + + string GetHTTP404(string host); + + string GetHTTP500(); + } +} diff --git a/OpenSim/Framework/Servers/HttpServer/Interfaces/IStreamHandler.cs b/OpenSim/Framework/Servers/HttpServer/Interfaces/IStreamHandler.cs new file mode 100644 index 0000000000..6e27aba050 --- /dev/null +++ b/OpenSim/Framework/Servers/HttpServer/Interfaces/IStreamHandler.cs @@ -0,0 +1,61 @@ +/* + * 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.Collections; +using System.IO; + +namespace OpenSim.Framework.Servers.HttpServer +{ + public interface IRequestHandler + { + // Return response content type + string ContentType { get; } + + // Return required http method + string HttpMethod { get; } + + // Return path + string Path { get; } + } + + public interface IStreamedRequestHandler : IRequestHandler + { + // Handle request stream, return byte array + byte[] Handle(string path, Stream request, OSHttpRequest httpRequest, OSHttpResponse httpResponse); + } + + public interface IStreamHandler : IRequestHandler + { + // Handle request stream, return byte array + void Handle(string path, Stream request, Stream response, OSHttpRequest httpReqbuest, OSHttpResponse httpResponse); + } + + public interface IGenericHTTPHandler : IRequestHandler + { + Hashtable Handle(string path, Hashtable request); + } +} diff --git a/OpenSim/Framework/Servers/HttpServer/Interfaces/OpenSim.Framework.Servers.Interfaces.csproj b/OpenSim/Framework/Servers/HttpServer/Interfaces/OpenSim.Framework.Servers.Interfaces.csproj new file mode 100644 index 0000000000..e8700f121d --- /dev/null +++ b/OpenSim/Framework/Servers/HttpServer/Interfaces/OpenSim.Framework.Servers.Interfaces.csproj @@ -0,0 +1,120 @@ + + + Local + 8.0.50727 + 2.0 + {8673D009-0000-0000-0000-000000000000} + Debug + AnyCPU + + + + OpenSim.Framework.Servers.Interfaces + JScript + Grid + IE50 + false + v2.0 + Library + + OpenSim.Framework.Servers.Interfaces + + + + + + + False + 285212672 + False + + + TRACE;DEBUG + + True + 4096 + False + ../../../../bin/ + False + False + False + 4 + False + + + + False + 285212672 + False + + + TRACE + + False + 4096 + True + ../../../../bin/ + False + False + False + 4 + False + + + + + HttpServer_OpenSim.dll + False + + + log4net.dll + False + + + OpenMetaverse.StructuredData.dll + False + + + OpenMetaverseTypes.dll + False + + + System + False + + + System.Xml + False + + + XMLRPC.dll + False + + + + + OpenSim.Data + {B75A430B-0000-0000-0000-000000000000} + {FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + False + + + + + Code + + + Code + + + Code + + + + + + + + + + diff --git a/OpenSim/Framework/Servers/HttpServer/Interfaces/OpenSim.Framework.Servers.Interfaces.csproj.user b/OpenSim/Framework/Servers/HttpServer/Interfaces/OpenSim.Framework.Servers.Interfaces.csproj.user new file mode 100644 index 0000000000..b73b33fceb --- /dev/null +++ b/OpenSim/Framework/Servers/HttpServer/Interfaces/OpenSim.Framework.Servers.Interfaces.csproj.user @@ -0,0 +1,12 @@ + + + Debug + AnyCPU + /root/opensim-commit/bin/ + 8.0.50727 + ProjectFiles + 0 + + + + diff --git a/OpenSim/Framework/Servers/HttpServer/Interfaces/OpenSim.Framework.Servers.Interfaces.dll.build b/OpenSim/Framework/Servers/HttpServer/Interfaces/OpenSim.Framework.Servers.Interfaces.dll.build new file mode 100644 index 0000000000..102300fc83 --- /dev/null +++ b/OpenSim/Framework/Servers/HttpServer/Interfaces/OpenSim.Framework.Servers.Interfaces.dll.build @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/OpenSim/Framework/Servers/HttpServer/Interfaces/OpenSim.Framework.Servers.Interfaces.mdp b/OpenSim/Framework/Servers/HttpServer/Interfaces/OpenSim.Framework.Servers.Interfaces.mdp new file mode 100644 index 0000000000..96f6b46e89 --- /dev/null +++ b/OpenSim/Framework/Servers/HttpServer/Interfaces/OpenSim.Framework.Servers.Interfaces.mdp @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/OpenSim/Framework/Servers/HttpServer/LLSDMethod.cs b/OpenSim/Framework/Servers/HttpServer/LLSDMethod.cs new file mode 100644 index 0000000000..d669182699 --- /dev/null +++ b/OpenSim/Framework/Servers/HttpServer/LLSDMethod.cs @@ -0,0 +1,34 @@ +/* + * 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 OpenMetaverse.StructuredData; + +namespace OpenSim.Framework.Servers.HttpServer +{ + public delegate OSD LLSDMethod( string path, OSD request, string endpoint ); + public delegate OSD DefaultLLSDMethod(OSD request); +} diff --git a/OpenSim/Framework/Servers/HttpServer/LLSDMethodString.cs b/OpenSim/Framework/Servers/HttpServer/LLSDMethodString.cs new file mode 100644 index 0000000000..61def78ab1 --- /dev/null +++ b/OpenSim/Framework/Servers/HttpServer/LLSDMethodString.cs @@ -0,0 +1,33 @@ +/* + * 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 OpenMetaverse.StructuredData; + +namespace OpenSim.Framework.Servers.HttpServer +{ + public delegate OSD LLSDMethodString(OSD request, string thePath); +} diff --git a/OpenSim/Framework/Servers/HttpServer/OSHttpHandler.cs b/OpenSim/Framework/Servers/HttpServer/OSHttpHandler.cs new file mode 100644 index 0000000000..f1788a00cc --- /dev/null +++ b/OpenSim/Framework/Servers/HttpServer/OSHttpHandler.cs @@ -0,0 +1,183 @@ +/* + * 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.Collections.Generic; +using System.IO; +using System.Text.RegularExpressions; + +namespace OpenSim.Framework.Servers.HttpServer +{ + /// + /// Any OSHttpHandler must return one of the following results: + /// + /// + /// result code + /// meaning + /// + /// + /// Pass + /// handler did not process the request + /// + /// + /// Done + /// handler did process the request, OSHttpServer + /// can clean up and close the request + /// + /// + /// + public enum OSHttpHandlerResult + { + Unprocessed, + Pass, + Done, + } + + /// + /// An OSHttpHandler that matches on the "content-type" header can + /// supply an OSHttpContentTypeChecker delegate which will be + /// invoked by the request matcher in OSHttpRequestPump. + /// + /// true if the handler is interested in the content; + /// false otherwise + public delegate bool OSHttpContentTypeChecker(OSHttpRequest req); + + public abstract class OSHttpHandler + { + /// + /// Regular expression used to match against method of + /// the incoming HTTP request. If you want to match any string + /// either use '.*' or null. To match on the empty string use + /// '^$'. + /// + public virtual Regex Method + { + get { return _method; } + } + protected Regex _method; + + /// + /// Regular expression used to match against path of the + /// incoming HTTP request. If you want to match any string + /// either use '.*' or null. To match on the emtpy string use + /// '^$'. + /// + public virtual Regex Path + { + get { return _path; } + } + protected Regex _path; + + /// + /// Dictionary of (query name, regular expression) tuples, + /// allowing us to match on URI query fields. + /// + public virtual Dictionary Query + { + get { return _query; } + } + protected Dictionary _query; + + /// + /// Dictionary of (header name, regular expression) tuples, + /// allowing us to match on HTTP header fields. + /// + public virtual Dictionary Headers + { + get { return _headers; } + } + protected Dictionary _headers; + + /// + /// Dictionary of (header name, regular expression) tuples, + /// allowing us to match on HTTP header fields. + /// + /// + /// This feature is currently not implemented as it requires + /// (trivial) changes to HttpServer.HttpListener that have not + /// been implemented. + /// + public virtual Regex IPEndPointWhitelist + { + get { return _ipEndPointRegex; } + } + protected Regex _ipEndPointRegex; + + + /// + /// Base class constructor. + /// + /// null or path regex + /// null or dictionary of header + /// regexs + /// null or content type + /// regex + /// null or IP address regex + public OSHttpHandler(Regex method, Regex path, Dictionary query, + Dictionary headers, Regex contentType, Regex whitelist) + { + _method = method; + _path = path; + _query = query; + _ipEndPointRegex = whitelist; + + if (null == _headers && null != contentType) + { + _headers = new Dictionary(); + _headers.Add("content-type", contentType); + } + } + + + /// + /// Process an incoming OSHttpRequest that matched our + /// requirements. + /// + /// + /// OSHttpHandlerResult.Pass if we are after all not + /// interested in the request; OSHttpHandlerResult.Done if we + /// did process the request. + /// + public abstract OSHttpHandlerResult Process(OSHttpRequest request); + + public override string ToString() + { + StringWriter sw = new StringWriter(); + sw.WriteLine("{0}", base.ToString()); + sw.WriteLine(" method regex {0}", null == Method ? "null" : Method.ToString()); + sw.WriteLine(" path regex {0}", null == Path ? "null": Path.ToString()); + foreach (string tag in Headers.Keys) + { + sw.WriteLine(" header {0} : {1}", tag, Headers[tag].ToString()); + } + sw.WriteLine(" IP whitelist {0}", null == IPEndPointWhitelist ? "null" : IPEndPointWhitelist.ToString()); + sw.WriteLine(); + sw.Close(); + return sw.ToString(); + } + } +} diff --git a/OpenSim/Framework/Servers/HttpServer/OSHttpHttpHandler.cs b/OpenSim/Framework/Servers/HttpServer/OSHttpHttpHandler.cs new file mode 100644 index 0000000000..09d6f523ac --- /dev/null +++ b/OpenSim/Framework/Servers/HttpServer/OSHttpHttpHandler.cs @@ -0,0 +1,145 @@ +/* + * 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.Collections; +using System.Collections.Generic; +using System.IO; +using System.Net; +using System.Reflection; +using System.Text; +using System.Text.RegularExpressions; +using System.Xml; +using log4net; +using Nwc.XmlRpc; + +namespace OpenSim.Framework.Servers.HttpServer +{ + public delegate XmlRpcResponse OSHttpHttpProcessor(XmlRpcRequest request); + + public class OSHttpHttpHandler: OSHttpHandler + { + private static readonly ILog _log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + // contains handler for processing HTTP Request + private GenericHTTPMethod _handler; + + /// + /// Instantiate an HTTP handler. + /// + /// a GenericHTTPMethod + /// null or HTTP method regex + /// null or path regex + /// null or dictionary with query regexs + /// null or dictionary with header + /// regexs + /// null or IP address whitelist + public OSHttpHttpHandler(GenericHTTPMethod handler, Regex method, Regex path, + Dictionary query, + Dictionary headers, Regex whitelist) + : base(method, path, query, headers, new Regex(@"^text/html", RegexOptions.IgnoreCase | RegexOptions.Compiled), + whitelist) + { + _handler = handler; + } + + /// + /// Instantiate an HTTP handler. + /// + /// a GenericHTTPMethod + public OSHttpHttpHandler(GenericHTTPMethod handler) + : this(handler, new Regex(@"^GET$", RegexOptions.IgnoreCase | RegexOptions.Compiled), null, null, null, null) + { + } + + /// + /// Invoked by OSHttpRequestPump. + /// + public override OSHttpHandlerResult Process(OSHttpRequest request) + { + // call handler method + Hashtable responseData = _handler(request.Query); + + int responseCode = (int)responseData["int_response_code"]; + string responseString = (string)responseData["str_response_string"]; + string contentType = (string)responseData["content_type"]; + + //Even though only one other part of the entire code uses HTTPHandlers, we shouldn't expect this + //and should check for NullReferenceExceptions + + if (string.IsNullOrEmpty(contentType)) + { + contentType = "text/html"; + } + + OSHttpResponse response = new OSHttpResponse(request); + + // We're forgoing the usual error status codes here because the client + // ignores anything but 200 and 301 + + response.StatusCode = (int)OSHttpStatusCode.SuccessOk; + + if (responseCode == (int)OSHttpStatusCode.RedirectMovedPermanently) + { + response.RedirectLocation = (string)responseData["str_redirect_location"]; + response.StatusCode = responseCode; + } + + response.AddHeader("Content-type", contentType); + + byte[] buffer; + + if (!contentType.Contains("image")) + { + buffer = Encoding.UTF8.GetBytes(responseString); + } + else + { + buffer = Convert.FromBase64String(responseString); + } + + response.SendChunked = false; + response.ContentLength64 = buffer.Length; + response.ContentEncoding = Encoding.UTF8; + + try + { + response.Body.Write(buffer, 0, buffer.Length); + } + catch (Exception ex) + { + _log.ErrorFormat("[OSHttpHttpHandler]: Error: {0}", ex.Message); + } + finally + { + response.Send(); + } + + return OSHttpHandlerResult.Done; + } + } +} diff --git a/OpenSim/Framework/Servers/HttpServer/OSHttpRequest.cs b/OpenSim/Framework/Servers/HttpServer/OSHttpRequest.cs new file mode 100644 index 0000000000..0ca868ca82 --- /dev/null +++ b/OpenSim/Framework/Servers/HttpServer/OSHttpRequest.cs @@ -0,0 +1,228 @@ +/* + * 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.Collections; +using System.Collections.Generic; +using System.Collections.Specialized; +using System.IO; +using System.Net; +using System.Reflection; +using System.Text; +using HttpServer; +using log4net; + +namespace OpenSim.Framework.Servers.HttpServer +{ + public class OSHttpRequest + { + private static readonly ILog _log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + protected IHttpRequest _request = null; + protected IHttpClientContext _context = null; + + public string[] AcceptTypes + { + get { return _request.AcceptTypes; } + } + + public Encoding ContentEncoding + { + get { return _contentEncoding; } + } + private Encoding _contentEncoding; + + public long ContentLength + { + get { return _request.ContentLength; } + } + + public long ContentLength64 + { + get { return ContentLength; } + } + + public string ContentType + { + get { return _contentType; } + } + private string _contentType; + + public bool HasEntityBody + { + get { return _request.ContentLength != 0; } + } + + public NameValueCollection Headers + { + get { return _request.Headers; } + } + + public string HttpMethod + { + get { return _request.Method; } + } + + public Stream InputStream + { + get { return _request.Body; } + } + + public bool IsSecured + { + get { return _context.Secured; } + } + + public bool KeepAlive + { + get { return ConnectionType.KeepAlive == _request.Connection; } + } + + public NameValueCollection QueryString + { + get { return _queryString; } + } + private NameValueCollection _queryString; + + public Hashtable Query + { + get { return _query; } + } + private Hashtable _query; + + public string RawUrl + { + get { return _request.Uri.AbsolutePath; } + } + + public IPEndPoint RemoteIPEndPoint + { + get { return _remoteIPEndPoint; } + } + private IPEndPoint _remoteIPEndPoint; + + public Uri Url + { + get { return _request.Uri; } + } + + public string UserAgent + { + get { return _userAgent; } + } + private string _userAgent; + + internal IHttpRequest IHttpRequest + { + get { return _request; } + } + + internal IHttpClientContext IHttpClientContext + { + get { return _context; } + } + + /// + /// Internal whiteboard for handlers to store temporary stuff + /// into. + /// + internal Dictionary Whiteboard + { + get { return _whiteboard; } + } + private Dictionary _whiteboard = new Dictionary(); + + + public OSHttpRequest() {} + + public OSHttpRequest(IHttpClientContext context, IHttpRequest req) + { + _request = req; + _context = context; + + if (null != req.Headers["content-encoding"]) + _contentEncoding = Encoding.GetEncoding(_request.Headers["content-encoding"]); + if (null != req.Headers["content-type"]) + _contentType = _request.Headers["content-type"]; + if (null != req.Headers["user-agent"]) + _userAgent = req.Headers["user-agent"]; + if (null != req.Headers["remote_addr"]) + { + try + { + IPAddress addr = IPAddress.Parse(req.Headers["remote_addr"]); + int port = Int32.Parse(req.Headers["remote_port"]); + _remoteIPEndPoint = new IPEndPoint(addr, port); + } + catch (FormatException) + { + _log.ErrorFormat("[OSHttpRequest]: format exception on addr/port {0}:{1}, ignoring", + req.Headers["remote_addr"], req.Headers["remote_port"]); + } + } + + _queryString = new NameValueCollection(); + _query = new Hashtable(); + try + { + foreach (HttpInputItem item in req.QueryString) + { + try + { + _queryString.Add(item.Name, item.Value); + _query[item.Name] = item.Value; + } + catch (InvalidCastException) + { + _log.DebugFormat("[OSHttpRequest]: error parsing {0} query item, skipping it", item.Name); + continue; + } + } + } + catch (Exception) + { + _log.ErrorFormat("[OSHttpRequest]: Error parsing querystring"); + } + } + + public override string ToString() + { + StringBuilder me = new StringBuilder(); + me.Append(String.Format("OSHttpRequest: {0} {1}\n", HttpMethod, RawUrl)); + foreach (string k in Headers.AllKeys) + { + me.Append(String.Format(" {0}: {1}\n", k, Headers[k])); + } + if (null != RemoteIPEndPoint) + { + me.Append(String.Format(" IP: {0}\n", RemoteIPEndPoint)); + } + + return me.ToString(); + } + } +} diff --git a/OpenSim/Framework/Servers/HttpServer/OSHttpRequestPump.cs b/OpenSim/Framework/Servers/HttpServer/OSHttpRequestPump.cs new file mode 100644 index 0000000000..893fa1b89c --- /dev/null +++ b/OpenSim/Framework/Servers/HttpServer/OSHttpRequestPump.cs @@ -0,0 +1,298 @@ +/* + * 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. + */ + +// #define DEBUGGING + +using System; +using System.Collections.Generic; +using System.Collections.Specialized; +using System.Diagnostics; +using System.IO; +using System.Net; +using System.Reflection; +using System.Text.RegularExpressions; +using System.Threading; +using log4net; +using HttpServer; + +namespace OpenSim.Framework.Servers.HttpServer +{ + /// + /// An OSHttpRequestPump fetches incoming OSHttpRequest objects + /// from the OSHttpRequestQueue and feeds them to all subscribed + /// parties. Each OSHttpRequestPump encapsulates one thread to do + /// the work and there is a fixed number of pumps for each + /// OSHttpServer object. + /// + public class OSHttpRequestPump + { + private static readonly ILog _log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + protected OSHttpServer _server; + protected OSHttpRequestQueue _queue; + protected Thread _engine; + + private int _id; + + public string EngineID + { + get { return String.Format("{0} pump {1}", _server.EngineID, _id); } + } + + public OSHttpRequestPump(OSHttpServer server, OSHttpRequestQueue queue, int id) + { + _server = server; + _queue = queue; + _id = id; + + _engine = new Thread(new ThreadStart(Engine)); + _engine.Name = EngineID; + _engine.IsBackground = true; + _engine.Start(); + + ThreadTracker.Add(_engine); + } + + public static OSHttpRequestPump[] Pumps(OSHttpServer server, OSHttpRequestQueue queue, int poolSize) + { + OSHttpRequestPump[] pumps = new OSHttpRequestPump[poolSize]; + for (int i = 0; i < pumps.Length; i++) + { + pumps[i] = new OSHttpRequestPump(server, queue, i); + } + + return pumps; + } + + public void Start() + { + _engine = new Thread(new ThreadStart(Engine)); + _engine.Name = EngineID; + _engine.IsBackground = true; + _engine.Start(); + + ThreadTracker.Add(_engine); + } + + public void Engine() + { + OSHttpRequest req = null; + + while (true) + { + try + { + // dequeue an OSHttpRequest from OSHttpServer's + // request queue + req = _queue.Dequeue(); + + // get a copy of the list of registered handlers + List handlers = _server.OSHttpHandlers; + + // prune list and have it sorted from most + // specific to least specific + handlers = MatchHandlers(req, handlers); + + // process req: we try each handler in turn until + // we are either out of handlers or get back a + // Pass or Done + OSHttpHandlerResult rc = OSHttpHandlerResult.Unprocessed; + foreach (OSHttpHandler h in handlers) + { + rc = h.Process(req); + + // Pass: handler did not process the request, + // try next handler + if (OSHttpHandlerResult.Pass == rc) continue; + + // Handled: handler has processed the request + if (OSHttpHandlerResult.Done == rc) break; + + // hmm, something went wrong + throw new Exception(String.Format("[{0}] got unexpected OSHttpHandlerResult {1}", EngineID, rc)); + } + + if (OSHttpHandlerResult.Unprocessed == rc) + { + _log.InfoFormat("[{0}] OSHttpHandler: no handler registered for {1}", EngineID, req); + + // set up response header + OSHttpResponse resp = new OSHttpResponse(req); + resp.StatusCode = (int)OSHttpStatusCode.ClientErrorNotFound; + resp.StatusDescription = String.Format("no handler on call for {0}", req); + resp.ContentType = "text/html"; + + // add explanatory message + StreamWriter body = new StreamWriter(resp.Body); + body.WriteLine(""); + body.WriteLine("
Ooops...
"); + body.WriteLine(String.Format("

{0}

", resp.StatusDescription)); + body.WriteLine(""); + body.Flush(); + + // and ship it back + resp.Send(); + } + } + catch (Exception e) + { + _log.DebugFormat("[{0}] OSHttpHandler problem: {1}", EngineID, e.ToString()); + _log.ErrorFormat("[{0}] OSHttpHandler problem: {1}", EngineID, e.Message); + } + } + } + + protected List MatchHandlers(OSHttpRequest req, List handlers) + { + Dictionary scoredHandlers = new Dictionary(); + + _log.DebugFormat("[{0}] MatchHandlers for {1}", EngineID, req); + foreach (OSHttpHandler h in handlers) + { + // initial anchor + scoredHandlers[h] = 0; + + // first, check whether IPEndPointWhitelist applies + // and, if it does, whether client is on that white + // list. + if (null != h.IPEndPointWhitelist) + { + // TODO: following code requires code changes to + // HttpServer.HttpRequest to become functional + + IPEndPoint remote = req.RemoteIPEndPoint; + if (null != remote) + { + Match epm = h.IPEndPointWhitelist.Match(remote.ToString()); + if (!epm.Success) + { + scoredHandlers.Remove(h); + continue; + } + } + } + + if (null != h.Method) + { + Match m = h.Method.Match(req.HttpMethod); + if (!m.Success) + { + scoredHandlers.Remove(h); + continue; + } + scoredHandlers[h]++; + } + + // whitelist ok, now check path + if (null != h.Path) + { + Match m = h.Path.Match(req.RawUrl); + if (!m.Success) + { + scoredHandlers.Remove(h); + continue; + } + scoredHandlers[h] += m.ToString().Length; + } + + // whitelist & path ok, now check query string + if (null != h.Query) + { + int queriesMatch = MatchOnNameValueCollection(req.QueryString, h.Query); + if (0 == queriesMatch) + { + _log.DebugFormat("[{0}] request {1}", EngineID, req); + _log.DebugFormat("[{0}] dropping handler {1}", EngineID, h); + + scoredHandlers.Remove(h); + continue; + } + scoredHandlers[h] += queriesMatch; + } + + // whitelist, path, query string ok, now check headers + if (null != h.Headers) + { + int headersMatch = MatchOnNameValueCollection(req.Headers, h.Headers); + if (0 == headersMatch) + { + _log.DebugFormat("[{0}] request {1}", EngineID, req); + _log.DebugFormat("[{0}] dropping handler {1}", EngineID, h); + + scoredHandlers.Remove(h); + continue; + } + scoredHandlers[h] += headersMatch; + } + } + + List matchingHandlers = new List(scoredHandlers.Keys); + matchingHandlers.Sort(delegate(OSHttpHandler x, OSHttpHandler y) + { + return scoredHandlers[x] - scoredHandlers[y]; + }); + LogDumpHandlerList(matchingHandlers); + return matchingHandlers; + } + + protected int MatchOnNameValueCollection(NameValueCollection collection, Dictionary regexs) + { + int matched = 0; + + foreach (string tag in regexs.Keys) + { + // do we have a header "tag"? + if (null == collection[tag]) + { + return 0; + } + + // does the content of collection[tag] match + // the supplied regex? + Match cm = regexs[tag].Match(collection[tag]); + if (!cm.Success) + { + return 0; + } + + // ok: matches + matched++; + continue; + } + + return matched; + } + + [ConditionalAttribute("DEBUGGING")] + private void LogDumpHandlerList(List l) + { + _log.DebugFormat("[{0}] OSHttpHandlerList dump:", EngineID); + foreach (OSHttpHandler h in l) + _log.DebugFormat(" ", h.ToString()); + } + } +} diff --git a/OpenSim/Framework/Servers/HttpServer/OSHttpRequestQueue.cs b/OpenSim/Framework/Servers/HttpServer/OSHttpRequestQueue.cs new file mode 100644 index 0000000000..4e34b41178 --- /dev/null +++ b/OpenSim/Framework/Servers/HttpServer/OSHttpRequestQueue.cs @@ -0,0 +1,68 @@ +/* + * 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.Collections.Generic; +using System.Threading; +using HttpServer; + +namespace OpenSim.Framework.Servers.HttpServer +{ + /// + /// OSHttpRequestQueues are used to hand over incoming HTTP + /// requests to OSHttpRequestPump objects. + /// + public class OSHttpRequestQueue : Queue + { + private object _syncObject = new object(); + + new public void Enqueue(OSHttpRequest req) + { + lock (_syncObject) + { + base.Enqueue(req); + Monitor.Pulse(_syncObject); + } + } + + new public OSHttpRequest Dequeue() + { + OSHttpRequest req = null; + + lock (_syncObject) + { + while (null == req) + { + Monitor.Wait(_syncObject); + if (0 != this.Count) req = base.Dequeue(); + } + } + + return req; + } + } +} diff --git a/OpenSim/Framework/Servers/HttpServer/OSHttpResponse.cs b/OpenSim/Framework/Servers/HttpServer/OSHttpResponse.cs new file mode 100644 index 0000000000..210d122797 --- /dev/null +++ b/OpenSim/Framework/Servers/HttpServer/OSHttpResponse.cs @@ -0,0 +1,302 @@ +/* + * 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.IO; +using System.Net; +using System.Text; +using HttpServer; + +namespace OpenSim.Framework.Servers.HttpServer +{ + /// + /// OSHttpResponse is the OpenSim representation of an HTTP + /// response. + /// + public class OSHttpResponse + { + /// + /// Content type property. + /// + /// + /// Setting this property will also set IsContentTypeSet to + /// true. + /// + public string ContentType + { + get + { + return _httpResponse.ContentType; + } + + set + { + _httpResponse.ContentType = value; + } + } + + /// + /// Boolean property indicating whether the content type + /// property actively has been set. + /// + /// + /// IsContentTypeSet will go away together with .NET base. + /// + // public bool IsContentTypeSet + // { + // get { return _contentTypeSet; } + // } + // private bool _contentTypeSet; + + + /// + /// Length of the body content; 0 if there is no body. + /// + public long ContentLength + { + get + { + return _httpResponse.ContentLength; + } + + set + { + _httpResponse.ContentLength = value; + } + } + + /// + /// Alias for ContentLength. + /// + public long ContentLength64 + { + get { return ContentLength; } + set { ContentLength = value; } + } + + /// + /// Encoding of the body content. + /// + public Encoding ContentEncoding + { + get + { + return _httpResponse.Encoding; + } + + set + { + _httpResponse.Encoding = value; + } + } + + public bool KeepAlive + { + get + { + return _httpResponse.Connection == ConnectionType.KeepAlive; + } + + set + { + if (value) + _httpResponse.Connection = ConnectionType.KeepAlive; + else + _httpResponse.Connection = ConnectionType.Close; + } + } + + /// + /// Get or set the keep alive timeout property (default is + /// 20). Setting this to 0 also disables KeepAlive. Setting + /// this to something else but 0 also enable KeepAlive. + /// + public int KeepAliveTimeout + { + get + { + return _httpResponse.KeepAlive; + } + + set + { + if (value == 0) + { + _httpResponse.Connection = ConnectionType.Close; + _httpResponse.KeepAlive = 0; + } + else + { + _httpResponse.Connection = ConnectionType.KeepAlive; + _httpResponse.KeepAlive = value; + } + } + } + + /// + /// Return the output stream feeding the body. + /// + /// + /// On its way out... + /// + public Stream OutputStream + { + get + { + return _httpResponse.Body; + } + } + + public string ProtocolVersion + { + get + { + return _httpResponse.ProtocolVersion; + } + + set + { + _httpResponse.ProtocolVersion = value; + } + } + + /// + /// Return the output stream feeding the body. + /// + public Stream Body + { + get + { + return _httpResponse.Body; + } + } + + /// + /// Set a redirct location. + /// + public string RedirectLocation + { + // get { return _redirectLocation; } + set + { + _httpResponse.Redirect(value); + } + } + + + /// + /// Chunk transfers. + /// + public bool SendChunked + { + get + { + return _httpResponse.Chunked; + } + + set + { + _httpResponse.Chunked = value; + } + } + + /// + /// HTTP status code. + /// + public int StatusCode + { + get + { + return (int)_httpResponse.Status; + } + + set + { + _httpResponse.Status = (HttpStatusCode)value; + } + } + + + /// + /// HTTP status description. + /// + public string StatusDescription + { + get + { + return _httpResponse.Reason; + } + + set + { + _httpResponse.Reason = value; + } + } + + + protected IHttpResponse _httpResponse; + + public OSHttpResponse() {} + + public OSHttpResponse(IHttpResponse resp) + { + _httpResponse = resp; + } + + /// + /// Instantiate an OSHttpResponse object from an OSHttpRequest + /// object. + /// Incoming OSHttpRequest to which we are + /// replying + public OSHttpResponse(OSHttpRequest req) + { + _httpResponse = new HttpResponse(req.IHttpClientContext, req.IHttpRequest); + } + + /// + /// Add a header field and content to the response. + /// + /// string containing the header field + /// name + /// string containing the header field + /// value + public void AddHeader(string key, string value) + { + _httpResponse.AddHeader(key, value); + } + + /// + /// Send the response back to the remote client + /// + public void Send() + { + _httpResponse.Body.Flush(); + _httpResponse.Send(); + + } + } +} diff --git a/OpenSim/Framework/Servers/HttpServer/OSHttpServer.cs b/OpenSim/Framework/Servers/HttpServer/OSHttpServer.cs new file mode 100644 index 0000000000..e84f314708 --- /dev/null +++ b/OpenSim/Framework/Servers/HttpServer/OSHttpServer.cs @@ -0,0 +1,210 @@ +/* + * 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.Collections.Generic; +using System.Net; +using System.Net.Sockets; +using System.Reflection; +using System.Text.RegularExpressions; +using System.Threading; +using System.Security.Cryptography.X509Certificates; +using log4net; +using HttpServer; + +using HttpListener = HttpServer.HttpListener; + +namespace OpenSim.Framework.Servers.HttpServer +{ + /// + /// OSHttpServer provides an HTTP server bound to a specific + /// port. When instantiated with just address and port it uses + /// normal HTTP, when instantiated with address, port, and X509 + /// certificate, it uses HTTPS. + /// + public class OSHttpServer + { + private static readonly ILog _log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + private object _syncObject = new object(); + + // underlying HttpServer.HttpListener + protected HttpListener _listener; + // underlying core/engine thread + protected Thread _engine; + + // Queue containing (OS)HttpRequests + protected OSHttpRequestQueue _queue; + + // OSHttpRequestPumps "pumping" incoming OSHttpRequests + // upwards + protected OSHttpRequestPump[] _pumps; + + // thread identifier + protected string _engineId; + public string EngineID + { + get { return _engineId; } + } + + /// + /// True if this is an HTTPS connection; false otherwise. + /// + protected bool _isSecure; + public bool IsSecure + { + get { return _isSecure; } + } + + public int QueueSize + { + get { return _pumps.Length; } + } + + /// + /// List of registered OSHttpHandlers for this OSHttpServer instance. + /// + protected List _httpHandlers = new List(); + public List OSHttpHandlers + { + get + { + lock (_httpHandlers) + { + return new List(_httpHandlers); + } + } + } + + + /// + /// Instantiate an HTTP server. + /// + public OSHttpServer(IPAddress address, int port, int poolSize) + { + _engineId = String.Format("OSHttpServer (HTTP:{0})", port); + _isSecure = false; + _log.DebugFormat("[{0}] HTTP server instantiated", EngineID); + + _listener = new HttpListener(address, port); + _queue = new OSHttpRequestQueue(); + _pumps = OSHttpRequestPump.Pumps(this, _queue, poolSize); + } + + /// + /// Instantiate an HTTPS server. + /// + public OSHttpServer(IPAddress address, int port, X509Certificate certificate, int poolSize) + { + _engineId = String.Format("OSHttpServer [HTTPS:{0}/ps:{1}]", port, poolSize); + _isSecure = true; + _log.DebugFormat("[{0}] HTTPS server instantiated", EngineID); + + _listener = new HttpListener(address, port, certificate); + _queue = new OSHttpRequestQueue(); + _pumps = OSHttpRequestPump.Pumps(this, _queue, poolSize); + } + + /// + /// Turn an HttpRequest into an OSHttpRequestItem and place it + /// in the queue. The OSHttpRequestQueue object will pulse the + /// next available idle pump. + /// + protected void OnHttpRequest(HttpClientContext client, HttpRequest request) + { + // turn request into OSHttpRequest + OSHttpRequest req = new OSHttpRequest(client, request); + + // place OSHttpRequest into _httpRequestQueue, will + // trigger Pulse to idle waiting pumps + _queue.Enqueue(req); + } + + /// + /// Start the HTTP server engine. + /// + public void Start() + { + _engine = new Thread(new ThreadStart(Engine)); + _engine.Name = _engineId; + _engine.IsBackground = true; + _engine.Start(); + + ThreadTracker.Add(_engine); + + // start the pumps... + for (int i = 0; i < _pumps.Length; i++) + _pumps[i].Start(); + } + + public void Stop() + { + lock (_syncObject) Monitor.Pulse(_syncObject); + } + + /// + /// Engine keeps the HTTP server running. + /// + private void Engine() + { + try { + _listener.RequestHandler += OnHttpRequest; + _listener.Start(QueueSize); + _log.InfoFormat("[{0}] HTTP server started", EngineID); + + lock (_syncObject) Monitor.Wait(_syncObject); + } + catch (Exception ex) + { + _log.DebugFormat("[{0}] HTTP server startup failed: {1}", EngineID, ex.ToString()); + } + + _log.InfoFormat("[{0}] HTTP server terminated", EngineID); + } + + + /// + /// Add an HTTP request handler. + /// + /// OSHttpHandler delegate + /// regex object for path matching + /// dictionary containing header names + /// and regular expressions to match against header values + public void AddHandler(OSHttpHandler handler) + { + lock (_httpHandlers) + { + if (_httpHandlers.Contains(handler)) + { + _log.DebugFormat("[OSHttpServer] attempt to add already existing handler ignored"); + return; + } + _httpHandlers.Add(handler); + } + } + } +} diff --git a/OpenSim/Framework/Servers/HttpServer/OSHttpStatusCodes.cs b/OpenSim/Framework/Servers/HttpServer/OSHttpStatusCodes.cs new file mode 100644 index 0000000000..2f1ca0fed5 --- /dev/null +++ b/OpenSim/Framework/Servers/HttpServer/OSHttpStatusCodes.cs @@ -0,0 +1,170 @@ +/* + * 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.HttpServer +{ + /// + /// 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, + // 499 Client error: Wildcard error. + ClientErrorJoker = 499, + + // 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, + } +} diff --git a/OpenSim/Framework/Servers/HttpServer/OSHttpXmlRpcHandler.cs b/OpenSim/Framework/Servers/HttpServer/OSHttpXmlRpcHandler.cs new file mode 100644 index 0000000000..49bae48625 --- /dev/null +++ b/OpenSim/Framework/Servers/HttpServer/OSHttpXmlRpcHandler.cs @@ -0,0 +1,180 @@ +/* + * 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.Collections.Generic; +using System.IO; +using System.Net; +using System.Reflection; +using System.Text; +using System.Text.RegularExpressions; +using System.Xml; +using log4net; +using Nwc.XmlRpc; + +namespace OpenSim.Framework.Servers.HttpServer +{ + public delegate XmlRpcResponse OSHttpXmlRpcProcessor(XmlRpcRequest request); + + public class OSHttpXmlRpcHandler: OSHttpHandler + { + private static readonly ILog _log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + /// + /// XmlRpcMethodMatch tries to reify (deserialize) an incoming + /// XmlRpc request (and posts it to the "whiteboard") and + /// checks whether the method name is one we are interested + /// in. + /// + /// true if the handler is interested in the content; + /// false otherwise + protected bool XmlRpcMethodMatch(OSHttpRequest req) + { + XmlRpcRequest xmlRpcRequest = null; + + // check whether req is already reified + // if not: reify (and post to whiteboard) + try + { + if (req.Whiteboard.ContainsKey("xmlrequest")) + { + xmlRpcRequest = req.Whiteboard["xmlrequest"] as XmlRpcRequest; + } + else + { + StreamReader body = new StreamReader(req.InputStream); + string requestBody = body.ReadToEnd(); + xmlRpcRequest = (XmlRpcRequest)(new XmlRpcRequestDeserializer()).Deserialize(requestBody); + req.Whiteboard["xmlrequest"] = xmlRpcRequest; + } + } + catch (XmlException) + { + _log.ErrorFormat("[OSHttpXmlRpcHandler] failed to deserialize XmlRpcRequest from {0}", req.ToString()); + return false; + } + + // check against methodName + if ((null != xmlRpcRequest) + && !String.IsNullOrEmpty(xmlRpcRequest.MethodName) + && xmlRpcRequest.MethodName == _methodName) + { + _log.DebugFormat("[OSHttpXmlRpcHandler] located handler {0} for {1}", _methodName, req.ToString()); + return true; + } + + return false; + } + + // contains handler for processing XmlRpc Request + private XmlRpcMethod _handler; + + // contains XmlRpc method name + private string _methodName; + + + /// + /// Instantiate an XmlRpc handler. + /// + /// XmlRpcMethod + /// delegate + /// XmlRpc method name + /// XmlRpc path prefix (regular expression) + /// Dictionary with header names and + /// regular expressions to match content of headers + /// IP whitelist of remote end points + /// to accept (regular expression) + /// + /// Except for handler and methodName, all other parameters + /// can be null, in which case they are not taken into account + /// when the handler is being looked up. + /// + public OSHttpXmlRpcHandler(XmlRpcMethod handler, string methodName, Regex path, + Dictionary headers, Regex whitelist) + : base(new Regex(@"^POST$", RegexOptions.IgnoreCase | RegexOptions.Compiled), path, null, headers, + new Regex(@"^(text|application)/xml", RegexOptions.IgnoreCase | RegexOptions.Compiled), + whitelist) + { + _handler = handler; + _methodName = methodName; + } + + + /// + /// Instantiate an XmlRpc handler. + /// + /// XmlRpcMethod + /// delegate + /// XmlRpc method name + public OSHttpXmlRpcHandler(XmlRpcMethod handler, string methodName) + : this(handler, methodName, null, null, null) + { + } + + + /// + /// Invoked by OSHttpRequestPump. + /// + public override OSHttpHandlerResult Process(OSHttpRequest request) + { + XmlRpcResponse xmlRpcResponse; + string responseString; + + // check whether we are interested in this request + if (!XmlRpcMethodMatch(request)) return OSHttpHandlerResult.Pass; + + + OSHttpResponse resp = new OSHttpResponse(request); + try + { + // reified XmlRpcRequest must still be on the whiteboard + XmlRpcRequest xmlRpcRequest = request.Whiteboard["xmlrequest"] as XmlRpcRequest; + xmlRpcResponse = _handler(xmlRpcRequest); + responseString = XmlRpcResponseSerializer.Singleton.Serialize(xmlRpcResponse); + + resp.ContentType = "text/xml"; + byte[] buffer = Encoding.UTF8.GetBytes(responseString); + + resp.SendChunked = false; + resp.ContentLength = buffer.Length; + resp.ContentEncoding = Encoding.UTF8; + + resp.Body.Write(buffer, 0, buffer.Length); + resp.Body.Flush(); + + resp.Send(); + + } + catch (Exception ex) + { + _log.WarnFormat("[OSHttpXmlRpcHandler]: Error: {0}", ex.Message); + return OSHttpHandlerResult.Pass; + } + return OSHttpHandlerResult.Done; + } + } +} diff --git a/OpenSim/Framework/Servers/HttpServer/OpenSim.Framework.Servers.HttpServer.csproj b/OpenSim/Framework/Servers/HttpServer/OpenSim.Framework.Servers.HttpServer.csproj new file mode 100644 index 0000000000..097a2514ba --- /dev/null +++ b/OpenSim/Framework/Servers/HttpServer/OpenSim.Framework.Servers.HttpServer.csproj @@ -0,0 +1,180 @@ + + + Local + 8.0.50727 + 2.0 + {1CBD339A-0000-0000-0000-000000000000} + Debug + AnyCPU + + + + OpenSim.Framework.Servers.HttpServer + JScript + Grid + IE50 + false + v2.0 + Library + + OpenSim.Framework.Servers.HttpServer + + + + + + + False + 285212672 + False + + + TRACE;DEBUG + + True + 4096 + False + ../../../../bin/ + False + False + False + 4 + False + + + + False + 285212672 + False + + + TRACE + + False + 4096 + True + ../../../../bin/ + False + False + False + 4 + False + + + + + HttpServer_OpenSim.dll + False + + + log4net.dll + False + + + OpenMetaverse.StructuredData.dll + False + + + OpenMetaverseTypes.dll + False + + + System + False + + + System.Xml + False + + + XMLRPC.dll + False + + + + + OpenSim.Data + {B75A430B-0000-0000-0000-000000000000} + {FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + False + + + + + Code + + + Code + + + Code + + + Code + + + Code + + + Code + + + Code + + + Code + + + Code + + + Code + + + Code + + + Code + + + Code + + + Code + + + Code + + + Code + + + Code + + + Code + + + Code + + + Code + + + Code + + + Code + + + Code + + + + + + + + + + diff --git a/OpenSim/Framework/Servers/HttpServer/OpenSim.Framework.Servers.HttpServer.csproj.user b/OpenSim/Framework/Servers/HttpServer/OpenSim.Framework.Servers.HttpServer.csproj.user new file mode 100644 index 0000000000..b73b33fceb --- /dev/null +++ b/OpenSim/Framework/Servers/HttpServer/OpenSim.Framework.Servers.HttpServer.csproj.user @@ -0,0 +1,12 @@ + + + Debug + AnyCPU + /root/opensim-commit/bin/ + 8.0.50727 + ProjectFiles + 0 + + + + diff --git a/OpenSim/Framework/Servers/HttpServer/OpenSim.Framework.Servers.HttpServer.dll.build b/OpenSim/Framework/Servers/HttpServer/OpenSim.Framework.Servers.HttpServer.dll.build new file mode 100644 index 0000000000..f81470334a --- /dev/null +++ b/OpenSim/Framework/Servers/HttpServer/OpenSim.Framework.Servers.HttpServer.dll.build @@ -0,0 +1,74 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/OpenSim/Framework/Servers/HttpServer/OpenSim.Framework.Servers.HttpServer.mdp b/OpenSim/Framework/Servers/HttpServer/OpenSim.Framework.Servers.HttpServer.mdp new file mode 100644 index 0000000000..7556d59a03 --- /dev/null +++ b/OpenSim/Framework/Servers/HttpServer/OpenSim.Framework.Servers.HttpServer.mdp @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/OpenSim/Framework/Servers/HttpServer/RestDeserialiseHandler.cs b/OpenSim/Framework/Servers/HttpServer/RestDeserialiseHandler.cs new file mode 100644 index 0000000000..d5ab926794 --- /dev/null +++ b/OpenSim/Framework/Servers/HttpServer/RestDeserialiseHandler.cs @@ -0,0 +1,66 @@ +/* + * 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.IO; +using System.Xml; +using System.Xml.Serialization; + +namespace OpenSim.Framework.Servers.HttpServer +{ + public delegate TResponse RestDeserialiseMethod(TRequest request); + + public class RestDeserialiseHandler : BaseRequestHandler, IStreamHandler + where TRequest : new() + { + private RestDeserialiseMethod m_method; + + public RestDeserialiseHandler(string httpMethod, string path, RestDeserialiseMethod method) + : base(httpMethod, path) + { + m_method = method; + } + + public void Handle(string path, Stream request, Stream responseStream, + OSHttpRequest httpRequest, OSHttpResponse httpResponse) + { + TRequest deserial; + using (XmlTextReader xmlReader = new XmlTextReader(request)) + { + XmlSerializer deserializer = new XmlSerializer(typeof (TRequest)); + deserial = (TRequest) deserializer.Deserialize(xmlReader); + } + + TResponse response = m_method(deserial); + + using (XmlWriter xmlWriter = XmlTextWriter.Create(responseStream)) + { + XmlSerializer serializer = new XmlSerializer(typeof (TResponse)); + serializer.Serialize(xmlWriter, response); + } + } + } +} diff --git a/OpenSim/Framework/Servers/HttpServer/RestHTTPHandler.cs b/OpenSim/Framework/Servers/HttpServer/RestHTTPHandler.cs new file mode 100644 index 0000000000..175a0f2b4d --- /dev/null +++ b/OpenSim/Framework/Servers/HttpServer/RestHTTPHandler.cs @@ -0,0 +1,56 @@ +/* + * 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.Collections; + +namespace OpenSim.Framework.Servers.HttpServer +{ + public class RestHTTPHandler : BaseHTTPHandler + { + private GenericHTTPMethod m_dhttpMethod; + + public GenericHTTPMethod Method + { + get { return m_dhttpMethod; } + } + + public override Hashtable Handle(string path, Hashtable request) + { + + string param = GetParam(path); + request.Add("param", param); + request.Add("path", path); + return m_dhttpMethod(request); + } + + public RestHTTPHandler(string httpMethod, string path, GenericHTTPMethod dhttpMethod) + : base(httpMethod, path) + { + m_dhttpMethod = dhttpMethod; + } + } +} diff --git a/OpenSim/Framework/Servers/HttpServer/RestMethod.cs b/OpenSim/Framework/Servers/HttpServer/RestMethod.cs new file mode 100644 index 0000000000..08ee35a08a --- /dev/null +++ b/OpenSim/Framework/Servers/HttpServer/RestMethod.cs @@ -0,0 +1,32 @@ +/* + * 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.HttpServer +{ + public delegate string RestMethod(string request, string path, string param, + OSHttpRequest httpRequest, OSHttpResponse httpResponse); +} diff --git a/OpenSim/Framework/Servers/HttpServer/RestObjectPoster.cs b/OpenSim/Framework/Servers/HttpServer/RestObjectPoster.cs new file mode 100644 index 0000000000..5a424d861d --- /dev/null +++ b/OpenSim/Framework/Servers/HttpServer/RestObjectPoster.cs @@ -0,0 +1,84 @@ +/* + * 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.IO; +using System.Net; +using System.Text; +using System.Xml; +using System.Xml.Serialization; + +namespace OpenSim.Framework.Servers.HttpServer +{ + /// + /// Makes an asynchronous REST request which doesn't require us to do anything with the response. + /// + public class RestObjectPoster + { + public static void BeginPostObject(string requestUrl, TRequest obj) + { + BeginPostObject("POST", requestUrl, obj); + } + + public static void BeginPostObject(string verb, string requestUrl, TRequest obj) + { + Type type = typeof (TRequest); + + WebRequest request = WebRequest.Create(requestUrl); + request.Method = verb; + request.ContentType = "text/xml"; + + MemoryStream buffer = new MemoryStream(); + + XmlWriterSettings settings = new XmlWriterSettings(); + settings.Encoding = Encoding.UTF8; + + using (XmlWriter writer = XmlWriter.Create(buffer, settings)) + { + XmlSerializer serializer = new XmlSerializer(type); + serializer.Serialize(writer, obj); + writer.Flush(); + } + + int length = (int) buffer.Length; + request.ContentLength = length; + + Stream requestStream = request.GetRequestStream(); + requestStream.Write(buffer.ToArray(), 0, length); + // IAsyncResult result = request.BeginGetResponse(AsyncCallback, request); + request.BeginGetResponse(AsyncCallback, request); + } + + private static void AsyncCallback(IAsyncResult result) + { + WebRequest request = (WebRequest) result.AsyncState; + using (WebResponse resp = request.EndGetResponse(result)) + { + } + } + } +} diff --git a/OpenSim/Framework/Servers/HttpServer/RestObjectPosterResponse.cs b/OpenSim/Framework/Servers/HttpServer/RestObjectPosterResponse.cs new file mode 100644 index 0000000000..690c583784 --- /dev/null +++ b/OpenSim/Framework/Servers/HttpServer/RestObjectPosterResponse.cs @@ -0,0 +1,107 @@ +/* + * 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.IO; +using System.Net; +using System.Text; +using System.Xml; +using System.Xml.Serialization; + +namespace OpenSim.Framework.Servers.HttpServer +{ + public delegate void ReturnResponse(T reponse); + + /// + /// Makes an asynchronous REST request with a callback to invoke with the response. + /// + public class RestObjectPosterResponse + { +// private static readonly log4net.ILog m_log +// = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); + + public ReturnResponse ResponseCallback; + + public void BeginPostObject(string requestUrl, TRequest obj) + { + BeginPostObject("POST", requestUrl, obj); + } + + public void BeginPostObject(string verb, string requestUrl, TRequest obj) + { + Type type = typeof (TRequest); + + WebRequest request = WebRequest.Create(requestUrl); + request.Method = verb; + request.ContentType = "text/xml"; + request.Timeout = 10000; + + MemoryStream buffer = new MemoryStream(); + + XmlWriterSettings settings = new XmlWriterSettings(); + settings.Encoding = Encoding.UTF8; + + using (XmlWriter writer = XmlWriter.Create(buffer, settings)) + { + XmlSerializer serializer = new XmlSerializer(type); + serializer.Serialize(writer, obj); + writer.Flush(); + } + + int length = (int) buffer.Length; + request.ContentLength = length; + + Stream requestStream = request.GetRequestStream(); + requestStream.Write(buffer.ToArray(), 0, length); + requestStream.Close(); + // IAsyncResult result = request.BeginGetResponse(AsyncCallback, request); + request.BeginGetResponse(AsyncCallback, request); + } + + private void AsyncCallback(IAsyncResult result) + { + WebRequest request = (WebRequest) result.AsyncState; + using (WebResponse resp = request.EndGetResponse(result)) + { + TResponse deserial; + XmlSerializer deserializer = new XmlSerializer(typeof (TResponse)); + Stream stream = resp.GetResponseStream(); + + // This is currently a bad debug stanza since it gobbles us the response... +// StreamReader reader = new StreamReader(stream); +// m_log.DebugFormat("[REST OBJECT POSTER RESPONSE]: Received {0}", reader.ReadToEnd()); + + deserial = (TResponse) deserializer.Deserialize(stream); + + if (deserial != null && ResponseCallback != null) + { + ResponseCallback(deserial); + } + } + } + } +} diff --git a/OpenSim/Framework/Servers/HttpServer/RestSessionService.cs b/OpenSim/Framework/Servers/HttpServer/RestSessionService.cs new file mode 100644 index 0000000000..f5e42483e9 --- /dev/null +++ b/OpenSim/Framework/Servers/HttpServer/RestSessionService.cs @@ -0,0 +1,291 @@ +/* + * 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 OpenSimulator 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.IO; +using System.Net; +using System.Reflection; +using System.Text; +using System.Xml; +using System.Xml.Serialization; +using log4net; + +namespace OpenSim.Framework.Servers.HttpServer +{ + public class RestSessionObject + { + private string sid; + private string aid; + private TRequest request_body; + + public string SessionID + { + get { return sid; } + set { sid = value; } + } + + public string AvatarID + { + get { return aid; } + set { aid = value; } + } + + public TRequest Body + { + get { return request_body; } + set { request_body = value; } + } + } + + public class SynchronousRestSessionObjectPoster + { + public static TResponse BeginPostObject(string verb, string requestUrl, TRequest obj, string sid, string aid) + { + RestSessionObject sobj = new RestSessionObject(); + sobj.SessionID = sid; + sobj.AvatarID = aid; + sobj.Body = obj; + + Type type = typeof(RestSessionObject); + + WebRequest request = WebRequest.Create(requestUrl); + request.Method = verb; + request.ContentType = "text/xml"; + + MemoryStream buffer = new MemoryStream(); + + XmlWriterSettings settings = new XmlWriterSettings(); + settings.Encoding = Encoding.UTF8; + + using (XmlWriter writer = XmlWriter.Create(buffer, settings)) + { + XmlSerializer serializer = new XmlSerializer(type); + serializer.Serialize(writer, sobj); + writer.Flush(); + } + + int length = (int)buffer.Length; + request.ContentLength = length; + + Stream requestStream = request.GetRequestStream(); + requestStream.Write(buffer.ToArray(), 0, length); + TResponse deserial = default(TResponse); + using (WebResponse resp = request.GetResponse()) + { + XmlSerializer deserializer = new XmlSerializer(typeof(TResponse)); + deserial = (TResponse)deserializer.Deserialize(resp.GetResponseStream()); + } + return deserial; + } + } + + public class RestSessionObjectPosterResponse + { + public ReturnResponse ResponseCallback; + + public void BeginPostObject(string requestUrl, TRequest obj, string sid, string aid) + { + BeginPostObject("POST", requestUrl, obj, sid, aid); + } + + public void BeginPostObject(string verb, string requestUrl, TRequest obj, string sid, string aid) + { + RestSessionObject sobj = new RestSessionObject(); + sobj.SessionID = sid; + sobj.AvatarID = aid; + sobj.Body = obj; + + Type type = typeof(RestSessionObject); + + WebRequest request = WebRequest.Create(requestUrl); + request.Method = verb; + request.ContentType = "text/xml"; + request.Timeout = 10000; + + MemoryStream buffer = new MemoryStream(); + + XmlWriterSettings settings = new XmlWriterSettings(); + settings.Encoding = Encoding.UTF8; + + using (XmlWriter writer = XmlWriter.Create(buffer, settings)) + { + XmlSerializer serializer = new XmlSerializer(type); + serializer.Serialize(writer, sobj); + writer.Flush(); + } + + int length = (int)buffer.Length; + request.ContentLength = length; + + Stream requestStream = request.GetRequestStream(); + requestStream.Write(buffer.ToArray(), 0, length); + requestStream.Close(); + // IAsyncResult result = request.BeginGetResponse(AsyncCallback, request); + request.BeginGetResponse(AsyncCallback, request); + } + + private void AsyncCallback(IAsyncResult result) + { + WebRequest request = (WebRequest)result.AsyncState; + using (WebResponse resp = request.EndGetResponse(result)) + { + TResponse deserial; + XmlSerializer deserializer = new XmlSerializer(typeof(TResponse)); + Stream stream = resp.GetResponseStream(); + + // This is currently a bad debug stanza since it gobbles us the response... + // StreamReader reader = new StreamReader(stream); + // m_log.DebugFormat("[REST OBJECT POSTER RESPONSE]: Received {0}", reader.ReadToEnd()); + + deserial = (TResponse)deserializer.Deserialize(stream); + + if (deserial != null && ResponseCallback != null) + { + ResponseCallback(deserial); + } + } + } + } + + public delegate bool CheckIdentityMethod(string sid, string aid); + + public class RestDeserialiseSecureHandler : BaseRequestHandler, IStreamHandler + where TRequest : new() + { + private static readonly ILog m_log + = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + private RestDeserialiseMethod m_method; + private CheckIdentityMethod m_smethod; + + public RestDeserialiseSecureHandler( + string httpMethod, string path, + RestDeserialiseMethod method, CheckIdentityMethod smethod) + : base(httpMethod, path) + { + m_smethod = smethod; + m_method = method; + } + + public void Handle(string path, Stream request, Stream responseStream, + OSHttpRequest httpRequest, OSHttpResponse httpResponse) + { + RestSessionObject deserial = default(RestSessionObject); + bool fail = false; + + using (XmlTextReader xmlReader = new XmlTextReader(request)) + { + try + { + XmlSerializer deserializer = new XmlSerializer(typeof(RestSessionObject)); + deserial = (RestSessionObject)deserializer.Deserialize(xmlReader); + } + catch (Exception e) + { + m_log.Error("[REST]: Deserialization problem. Ignoring request. " + e); + fail = true; + } + } + + TResponse response = default(TResponse); + if (!fail && m_smethod(deserial.SessionID, deserial.AvatarID)) + { + response = m_method(deserial.Body); + } + + using (XmlWriter xmlWriter = XmlTextWriter.Create(responseStream)) + { + XmlSerializer serializer = new XmlSerializer(typeof(TResponse)); + serializer.Serialize(xmlWriter, response); + } + } + } + + public delegate bool CheckTrustedSourceMethod(IPEndPoint peer); + + public class RestDeserialiseTrustedHandler : BaseRequestHandler, IStreamHandler + where TRequest : new() + { + private static readonly ILog m_log + = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + /// + /// The operation to perform once trust has been established. + /// + /// + /// + /// + /// + private RestDeserialiseMethod m_method; + + /// + /// The method used to check whether a request is trusted. + /// + private CheckTrustedSourceMethod m_tmethod; + + public RestDeserialiseTrustedHandler(string httpMethod, string path, RestDeserialiseMethod method, CheckTrustedSourceMethod tmethod) + : base(httpMethod, path) + { + m_tmethod = tmethod; + m_method = method; + } + + public void Handle(string path, Stream request, Stream responseStream, + OSHttpRequest httpRequest, OSHttpResponse httpResponse) + { + TRequest deserial = default(TRequest); + bool fail = false; + + using (XmlTextReader xmlReader = new XmlTextReader(request)) + { + try + { + XmlSerializer deserializer = new XmlSerializer(typeof(TRequest)); + deserial = (TRequest)deserializer.Deserialize(xmlReader); + } + catch (Exception e) + { + m_log.Error("[REST]: Deserialization problem. Ignoring request. " + e); + fail = true; + } + } + + TResponse response = default(TResponse); + if (!fail && m_tmethod(httpRequest.RemoteIPEndPoint)) + { + response = m_method(deserial); + } + + using (XmlWriter xmlWriter = XmlTextWriter.Create(responseStream)) + { + XmlSerializer serializer = new XmlSerializer(typeof(TResponse)); + serializer.Serialize(xmlWriter, response); + } + } + } + +} diff --git a/OpenSim/Framework/Servers/HttpServer/RestStreamHandler.cs b/OpenSim/Framework/Servers/HttpServer/RestStreamHandler.cs new file mode 100644 index 0000000000..f213c153e3 --- /dev/null +++ b/OpenSim/Framework/Servers/HttpServer/RestStreamHandler.cs @@ -0,0 +1,61 @@ +/* + * 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.IO; +using System.Text; + +namespace OpenSim.Framework.Servers.HttpServer +{ + public class RestStreamHandler : BaseStreamHandler + { + private RestMethod m_restMethod; + + public RestMethod Method + { + get { return m_restMethod; } + } + + public override byte[] Handle(string path, Stream request, OSHttpRequest httpRequest, OSHttpResponse httpResponse) + { + Encoding encoding = Encoding.UTF8; + StreamReader streamReader = new StreamReader(request, encoding); + + string requestBody = streamReader.ReadToEnd(); + streamReader.Close(); + + string param = GetParam(path); + string responseString = m_restMethod(requestBody, path, param, httpRequest, httpResponse); + + return Encoding.UTF8.GetBytes(responseString); + } + + public RestStreamHandler(string httpMethod, string path, RestMethod restMethod) : base(httpMethod, path) + { + m_restMethod = restMethod; + } + } +} diff --git a/OpenSim/Framework/Servers/HttpServer/SynchronousRestObjectPoster.cs b/OpenSim/Framework/Servers/HttpServer/SynchronousRestObjectPoster.cs new file mode 100644 index 0000000000..b754c361e2 --- /dev/null +++ b/OpenSim/Framework/Servers/HttpServer/SynchronousRestObjectPoster.cs @@ -0,0 +1,83 @@ +/* + * 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.IO; +using System.Net; +using System.Text; +using System.Xml; +using System.Xml.Serialization; + +namespace OpenSim.Framework.Servers.HttpServer +{ + public class SynchronousRestObjectPoster + { + /// + /// Perform a synchronous REST request. + /// + /// + /// + /// + /// + /// + /// Thrown if we encounter a network issue while posting + /// the request. You'll want to make sure you deal with this as they're not uncommon + public static TResponse BeginPostObject(string verb, string requestUrl, TRequest obj) + { + Type type = typeof (TRequest); + + WebRequest request = WebRequest.Create(requestUrl); + request.Method = verb; + request.ContentType = "text/xml"; + + MemoryStream buffer = new MemoryStream(); + + XmlWriterSettings settings = new XmlWriterSettings(); + settings.Encoding = Encoding.UTF8; + + using (XmlWriter writer = XmlWriter.Create(buffer, settings)) + { + XmlSerializer serializer = new XmlSerializer(type); + serializer.Serialize(writer, obj); + writer.Flush(); + } + + int length = (int) buffer.Length; + request.ContentLength = length; + + Stream requestStream = request.GetRequestStream(); + requestStream.Write(buffer.ToArray(), 0, length); + TResponse deserial = default(TResponse); + using (WebResponse resp = request.GetResponse()) + { + XmlSerializer deserializer = new XmlSerializer(typeof (TResponse)); + deserial = (TResponse) deserializer.Deserialize(resp.GetResponseStream()); + } + return deserial; + } + } +} diff --git a/OpenSim/Framework/Servers/HttpServer/XmlRpcMethod.cs b/OpenSim/Framework/Servers/HttpServer/XmlRpcMethod.cs new file mode 100644 index 0000000000..843b3f7edf --- /dev/null +++ b/OpenSim/Framework/Servers/HttpServer/XmlRpcMethod.cs @@ -0,0 +1,33 @@ +/* + * 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 Nwc.XmlRpc; + +namespace OpenSim.Framework.Servers.HttpServer +{ + public delegate XmlRpcResponse XmlRpcMethod(XmlRpcRequest request); +} diff --git a/OpenSim/Framework/Servers/HttpServer/bin/Debug/OpenSim.Framework.Servers.HttpServer.dll b/OpenSim/Framework/Servers/HttpServer/bin/Debug/OpenSim.Framework.Servers.HttpServer.dll new file mode 100755 index 0000000000000000000000000000000000000000..a19134668c357a37012acec73de3e0f87f103bbf GIT binary patch literal 41472 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 literal 0 HcmV?d00001 diff --git a/OpenSim/Framework/Servers/HttpServer/bin/Debug/OpenSim.Framework.Servers.HttpServer.dll.mdb b/OpenSim/Framework/Servers/HttpServer/bin/Debug/OpenSim.Framework.Servers.HttpServer.dll.mdb new file mode 100644 index 0000000000000000000000000000000000000000..25a50b944347b66b97f0964a489e43e916944e00 GIT binary patch literal 14486 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 literal 0 HcmV?d00001 diff --git a/OpenSim/Framework/Servers/MessageServerInfo.cs b/OpenSim/Framework/Servers/MessageServerInfo.cs new file mode 100644 index 0000000000..17b5f10f19 --- /dev/null +++ b/OpenSim/Framework/Servers/MessageServerInfo.cs @@ -0,0 +1,48 @@ +/* + * 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.Collections.Generic; + +namespace OpenSim.Framework.Servers +{ + public class MessageServerInfo + { + public string URI; + public string sendkey; + public string recvkey; + public List responsibleForRegions; + + public MessageServerInfo() + { + } + + public override string ToString() + { + return URI; + } + } +} diff --git a/OpenSim/Framework/Servers/PostAssetStreamHandler.cs b/OpenSim/Framework/Servers/PostAssetStreamHandler.cs new file mode 100644 index 0000000000..419b4082bb --- /dev/null +++ b/OpenSim/Framework/Servers/PostAssetStreamHandler.cs @@ -0,0 +1,72 @@ +/* + * 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 OpenSimulator 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.IO; +using System.Reflection; +using System.Xml.Serialization; +using log4net; +using OpenMetaverse; +using OpenSim.Data; +using OpenSim.Framework; +using OpenSim.Framework.Servers.HttpServer; + +namespace OpenSim.Framework.Servers +{ + public class PostAssetStreamHandler : BaseStreamHandler + { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + // private OpenAsset_Main m_assetManager; + private IAssetDataPlugin m_assetProvider; + + public override byte[] Handle(string path, Stream request, + OSHttpRequest httpRequest, OSHttpResponse httpResponse) + { + string param = GetParam(path); + + UUID assetId; + if (param.Length > 0) + UUID.TryParse(param, out assetId); + // byte[] txBuffer = new byte[4096]; + + XmlSerializer xs = new XmlSerializer(typeof (AssetBase)); + AssetBase asset = (AssetBase) xs.Deserialize(request); + + m_log.InfoFormat("[REST]: Creating asset {0}", asset.FullID); + m_assetProvider.CreateAsset(asset); + + return new byte[] {}; + } + + public PostAssetStreamHandler(IAssetDataPlugin assetProvider) + : base("POST", "/assets") + { + // m_assetManager = assetManager; + m_assetProvider = assetProvider; + } + } +} diff --git a/OpenSim/Framework/Servers/Tests/OSHttpTests.cs b/OpenSim/Framework/Servers/Tests/OSHttpTests.cs new file mode 100644 index 0000000000..ee8ab0971d --- /dev/null +++ b/OpenSim/Framework/Servers/Tests/OSHttpTests.cs @@ -0,0 +1,394 @@ +/* + * 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.Collections.Specialized; +using System.IO; +using System.Net; +using System.Net.Sockets; +using System.Text; +using HttpServer; +using HttpServer.FormDecoders; +using NUnit.Framework; +using NUnit.Framework.SyntaxHelpers; +using OpenSim.Framework.Servers.HttpServer; + +namespace OpenSim.Framework.Servers.Tests +{ + [TestFixture] + public class OSHttpTests + { + // we need an IHttpClientContext for our tests + public class TestHttpClientContext: IHttpClientContext + { + private bool _secured; + public bool Secured + { + get { return _secured; } + } + + public TestHttpClientContext(bool secured) + { + _secured = secured; + } + + public void Disconnect(SocketError error) {} + public void Respond(string httpVersion, HttpStatusCode statusCode, string reason, string body) {} + public void Respond(string httpVersion, HttpStatusCode statusCode, string reason) {} + public void Respond(string body) {} + public void Send(byte[] buffer) {} + public void Send(byte[] buffer, int offset, int size) {} + } + + public class TestHttpRequest: IHttpRequest + { + public bool BodyIsComplete + { + get { return true; } + } + public string[] AcceptTypes + { + get {return _acceptTypes; } + } + private string[] _acceptTypes; + public Stream Body + { + get { return _body; } + set { _body = value;} + } + private Stream _body; + public ConnectionType Connection + { + get { return _connection; } + set { _connection = value; } + } + private ConnectionType _connection; + public int ContentLength + { + get { return _contentLength; } + set { _contentLength = value; } + } + private int _contentLength; + public NameValueCollection Headers + { + get { return _headers; } + } + private NameValueCollection _headers = new NameValueCollection(); + public string HttpVersion + { + get { return _httpVersion; } + set { _httpVersion = value; } + } + private string _httpVersion = null; + public string Method + { + get { return _method; } + set { _method = value; } + } + private string _method = null; + public HttpInput QueryString + { + get { return _queryString; } + } + private HttpInput _queryString = null; + public Uri Uri + { + get { return _uri; } + set { _uri = value; } + } + private Uri _uri = null; + public string[] UriParts + { + get { return _uri.Segments; } + } + public HttpParam Param + { + get { return null; } + } + public HttpForm Form + { + get { return null; } + } + public bool IsAjax + { + get { return false; } + } + public RequestCookies Cookies + { + get { return null; } + } + + public TestHttpRequest() {} + + public TestHttpRequest(string contentEncoding, string contentType, string userAgent, + string remoteAddr, string remotePort, string[] acceptTypes, + ConnectionType connectionType, int contentLength, Uri uri) + { + _headers["content-encoding"] = contentEncoding; + _headers["content-type"] = contentType; + _headers["user-agent"] = userAgent; + _headers["remote_addr"] = remoteAddr; + _headers["remote_port"] = remotePort; + + _acceptTypes = acceptTypes; + _connection = connectionType; + _contentLength = contentLength; + _uri = uri; + } + + public void DecodeBody(FormDecoderProvider providers) {} + public void SetCookies(RequestCookies cookies) {} + public void AddHeader(string name, string value) + { + _headers.Add(name, value); + } + public int AddToBody(byte[] bytes, int offset, int length) + { + return 0; + } + public void Clear() {} + + public object Clone() + { + TestHttpRequest clone = new TestHttpRequest(); + clone._acceptTypes = _acceptTypes; + clone._connection = _connection; + clone._contentLength = _contentLength; + clone._uri = _uri; + clone._headers = new NameValueCollection(_headers); + + return clone; + } + } + + public class TestHttpResponse: IHttpResponse + { + public Stream Body + { + get { return _body; } + + set { _body = value; } + } + private Stream _body; + + public string ProtocolVersion + { + get { return _protocolVersion; } + set { _protocolVersion = value; } + } + private string _protocolVersion; + + public bool Chunked + { + get { return _chunked; } + + set { _chunked = value; } + } + private bool _chunked; + + public ConnectionType Connection + { + get { return _connection; } + + set { _connection = value; } + } + private ConnectionType _connection; + + public Encoding Encoding + { + get { return _encoding; } + + set { _encoding = value; } + } + private Encoding _encoding; + + public int KeepAlive + { + get { return _keepAlive; } + + set { _keepAlive = value; } + } + private int _keepAlive; + + public HttpStatusCode Status + { + get { return _status; } + + set { _status = value; } + } + private HttpStatusCode _status; + + public string Reason + { + get { return _reason; } + + set { _reason = value; } + } + private string _reason; + + public long ContentLength + { + get { return _contentLength; } + + set { _contentLength = value; } + } + private long _contentLength; + + public string ContentType + { + get { return _contentType; } + + set { _contentType = value; } + } + private string _contentType; + + public bool HeadersSent + { + get { return _headersSent; } + } + private bool _headersSent; + + public bool Sent + { + get { return _sent; } + } + private bool _sent; + + public ResponseCookies Cookies + { + get { return _cookies; } + } + private ResponseCookies _cookies = null; + + public TestHttpResponse() + { + _headersSent = false; + _sent = false; + } + + public void AddHeader(string name, string value) {} + public void Send() + { + if (!_headersSent) SendHeaders(); + if (_sent) throw new InvalidOperationException("stuff already sent"); + _sent = true; + } + + public void SendBody(byte[] buffer, int offset, int count) + { + if (!_headersSent) SendHeaders(); + _sent = true; + } + public void SendBody(byte[] buffer) + { + if (!_headersSent) SendHeaders(); + _sent = true; + } + + public void SendHeaders() + { + if (_headersSent) throw new InvalidOperationException("headers already sent"); + _headersSent = true; + } + + public void Redirect(Uri uri) {} + public void Redirect(string url) {} + } + + + public OSHttpRequest req0; + public OSHttpRequest req1; + + public OSHttpResponse rsp0; + + public IPEndPoint ipEP0; + + [TestFixtureSetUp] + public void Init() + { + TestHttpRequest threq0 = new TestHttpRequest("utf-8", "text/xml", "OpenSim Test Agent", "192.168.0.1", "4711", + new string[] {"text/xml"}, + ConnectionType.KeepAlive, 4711, + new Uri("http://127.0.0.1/admin/inventory/Dr+Who/Tardis")); + threq0.Method = "GET"; + threq0.HttpVersion = HttpHelper.HTTP10; + + TestHttpRequest threq1 = new TestHttpRequest("utf-8", "text/xml", "OpenSim Test Agent", "192.168.0.1", "4711", + new string[] {"text/xml"}, + ConnectionType.KeepAlive, 4711, + new Uri("http://127.0.0.1/admin/inventory/Dr+Who/Tardis?a=0&b=1&c=2")); + threq1.Method = "POST"; + threq1.HttpVersion = HttpHelper.HTTP11; + threq1.Headers["x-wuff"] = "wuffwuff"; + threq1.Headers["www-authenticate"] = "go away"; + + req0 = new OSHttpRequest(new TestHttpClientContext(false), threq0); + req1 = new OSHttpRequest(new TestHttpClientContext(false), threq1); + + rsp0 = new OSHttpResponse(new TestHttpResponse()); + + ipEP0 = new IPEndPoint(IPAddress.Parse("192.168.0.1"), 4711); + + } + + [Test] + public void T000_OSHttpRequest() + { + Assert.That(req0.HttpMethod, Is.EqualTo("GET")); + Assert.That(req0.ContentType, Is.EqualTo("text/xml")); + Assert.That(req0.ContentLength, Is.EqualTo(4711)); + + Assert.That(req1.HttpMethod, Is.EqualTo("POST")); + } + + [Test] + public void T001_OSHttpRequestHeaderAccess() + { + Assert.That(req1.Headers["x-wuff"], Is.EqualTo("wuffwuff")); + Assert.That(req1.Headers.Get("x-wuff"), Is.EqualTo("wuffwuff")); + + Assert.That(req1.Headers["www-authenticate"], Is.EqualTo("go away")); + Assert.That(req1.Headers.Get("www-authenticate"), Is.EqualTo("go away")); + + Assert.That(req0.RemoteIPEndPoint, Is.EqualTo(ipEP0)); + } + + [Test] + public void T002_OSHttpRequestUriParsing() + { + Assert.That(req0.RawUrl, Is.EqualTo("/admin/inventory/Dr+Who/Tardis")); + Assert.That(req1.Url.ToString(), Is.EqualTo("http://127.0.0.1/admin/inventory/Dr+Who/Tardis?a=0&b=1&c=2")); + } + + [Test] + public void T100_OSHttpResponse() + { + rsp0.ContentType = "text/xml"; + Assert.That(rsp0.ContentType, Is.EqualTo("text/xml")); + } + } +} diff --git a/OpenSim/Framework/Servers/VersionInfo.cs b/OpenSim/Framework/Servers/VersionInfo.cs new file mode 100644 index 0000000000..bdf935408e --- /dev/null +++ b/OpenSim/Framework/Servers/VersionInfo.cs @@ -0,0 +1,53 @@ +/* + * 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 +{ + public class VersionInfo + { + /// + /// This is the OpenSim version string. Change this if you are releasing a new OpenSim version. + /// + public readonly static string Version = "OpenSimulator Server 0.6.4"; // stay with 27 chars (used in regioninfo) + + /// + /// This is the external interface version. It is separate from the OpenSimulator project version. + /// + /// This version number should be + /// increased by 1 every time a code change makes the previous OpenSimulator revision incompatible + /// with the new revision. This will usually be due to interregion or grid facing interface changes. + /// + /// Changes which are compatible with an older revision (e.g. older revisions experience degraded functionality + /// but not outright failure) do not need a version number increment. + /// + /// Having this version number allows the grid service to reject connections from regions running a version + /// of the code that is too old. + /// + /// + public readonly static int MajorInterfaceVersion = 3; + } +}