BaseHttpServer.cs 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  1. /*
  2. * Copyright (c) Contributors, http://www.openmetaverse.org/
  3. * See CONTRIBUTORS.TXT for a full list of copyright holders.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions are met:
  7. * * Redistributions of source code must retain the above copyright
  8. * notice, this list of conditions and the following disclaimer.
  9. * * Redistributions in binary form must reproduce the above copyright
  10. * notice, this list of conditions and the following disclaimer in the
  11. * documentation and/or other materials provided with the distribution.
  12. * * Neither the name of the OpenSim Project nor the
  13. * names of its contributors may be used to endorse or promote products
  14. * derived from this software without specific prior written permission.
  15. *
  16. * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS AND ANY
  17. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  18. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  19. * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
  20. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  21. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  22. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  23. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  24. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  25. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  26. *
  27. */
  28. using System;
  29. using System.Collections;
  30. using System.Collections.Generic;
  31. using System.IO;
  32. using System.Net;
  33. using System.Text;
  34. using System.Text.RegularExpressions;
  35. using System.Threading;
  36. using Nwc.XmlRpc;
  37. using OpenSim.Framework.Console;
  38. namespace OpenSim.Framework.Servers
  39. {
  40. public class BaseHttpServer
  41. {
  42. protected Thread m_workerThread;
  43. protected HttpListener m_httpListener;
  44. protected Dictionary<string, XmlRpcMethod> m_rpcHandlers = new Dictionary<string, XmlRpcMethod>();
  45. protected Dictionary<string, IStreamHandler> m_streamHandlers = new Dictionary<string, IStreamHandler>();
  46. protected int m_port;
  47. protected bool m_firstcaps = true;
  48. public BaseHttpServer(int port)
  49. {
  50. m_port = port;
  51. }
  52. public void AddStreamHandler( IStreamHandler handler)
  53. {
  54. string httpMethod = handler.HttpMethod;
  55. string path = handler.Path;
  56. string handlerKey = GetHandlerKey(httpMethod, path);
  57. m_streamHandlers.Add(handlerKey, handler);
  58. }
  59. private static string GetHandlerKey(string httpMethod, string path)
  60. {
  61. return httpMethod + ":" + path;
  62. }
  63. public bool AddXmlRPCHandler(string method, XmlRpcMethod handler)
  64. {
  65. if (!this.m_rpcHandlers.ContainsKey(method))
  66. {
  67. this.m_rpcHandlers.Add(method, handler);
  68. return true;
  69. }
  70. //must already have a handler for that path so return false
  71. return false;
  72. }
  73. public virtual void HandleRequest(Object stateinfo)
  74. {
  75. HttpListenerContext context = (HttpListenerContext)stateinfo;
  76. HttpListenerRequest request = context.Request;
  77. HttpListenerResponse response = context.Response;
  78. response.KeepAlive = false;
  79. response.SendChunked = false;
  80. string path = request.RawUrl;
  81. string handlerKey = GetHandlerKey( request.HttpMethod, path );
  82. IStreamHandler streamHandler;
  83. if (TryGetStreamHandler( handlerKey, out streamHandler))
  84. {
  85. byte[] buffer = streamHandler.Handle(path, request.InputStream);
  86. request.InputStream.Close();
  87. response.ContentType = streamHandler.ContentType;
  88. response.ContentLength64 = buffer.LongLength;
  89. response.OutputStream.Write(buffer, 0, buffer.Length);
  90. response.OutputStream.Close();
  91. }
  92. else
  93. {
  94. HandleXmlRpcRequests(request, response);
  95. }
  96. }
  97. private bool TryGetStreamHandler(string handlerKey, out IStreamHandler streamHandler)
  98. {
  99. string bestMatch = null;
  100. foreach (string pattern in m_streamHandlers.Keys)
  101. {
  102. if (handlerKey.StartsWith(pattern))
  103. {
  104. if (String.IsNullOrEmpty(bestMatch) || pattern.Length > bestMatch.Length)
  105. {
  106. bestMatch = pattern;
  107. }
  108. }
  109. }
  110. if (String.IsNullOrEmpty(bestMatch))
  111. {
  112. streamHandler = null;
  113. return false;
  114. }
  115. else
  116. {
  117. streamHandler = m_streamHandlers[bestMatch];
  118. return true;
  119. }
  120. }
  121. private void HandleXmlRpcRequests(HttpListenerRequest request, HttpListenerResponse response)
  122. {
  123. Stream requestStream = request.InputStream;
  124. Encoding encoding = Encoding.UTF8;
  125. StreamReader reader = new StreamReader(requestStream, encoding);
  126. string requestBody = reader.ReadToEnd();
  127. reader.Close();
  128. requestStream.Close();
  129. XmlRpcRequest xmlRprcRequest = (XmlRpcRequest)(new XmlRpcRequestDeserializer()).Deserialize(requestBody);
  130. string methodName = xmlRprcRequest.MethodName;
  131. XmlRpcResponse xmlRpcResponse;
  132. XmlRpcMethod method;
  133. if (this.m_rpcHandlers.TryGetValue(methodName, out method))
  134. {
  135. xmlRpcResponse = method(xmlRprcRequest);
  136. }
  137. else
  138. {
  139. xmlRpcResponse = new XmlRpcResponse();
  140. Hashtable unknownMethodError = new Hashtable();
  141. unknownMethodError["reason"] = "XmlRequest"; ;
  142. unknownMethodError["message"] = "Unknown Rpc Request ["+methodName+"]";
  143. unknownMethodError["login"] = "false";
  144. xmlRpcResponse.Value = unknownMethodError;
  145. }
  146. response.AddHeader("Content-type", "text/xml");
  147. string responseString = XmlRpcResponseSerializer.Singleton.Serialize(xmlRpcResponse);
  148. byte[] buffer = Encoding.UTF8.GetBytes(responseString);
  149. response.SendChunked = false;
  150. response.ContentLength64 = buffer.Length;
  151. response.ContentEncoding = Encoding.UTF8;
  152. response.OutputStream.Write(buffer, 0, buffer.Length);
  153. response.OutputStream.Close();
  154. }
  155. public void Start()
  156. {
  157. MainLog.Instance.WriteLine(LogPriority.LOW, "BaseHttpServer.cs: Starting up HTTP Server");
  158. m_workerThread = new Thread(new ThreadStart(StartHTTP));
  159. m_workerThread.IsBackground = true;
  160. m_workerThread.Start();
  161. }
  162. private void StartHTTP()
  163. {
  164. try
  165. {
  166. MainLog.Instance.WriteLine(LogPriority.LOW, "BaseHttpServer.cs: StartHTTP() - Spawned main thread OK");
  167. m_httpListener = new HttpListener();
  168. m_httpListener.Prefixes.Add("http://+:" + m_port + "/");
  169. m_httpListener.Start();
  170. HttpListenerContext context;
  171. while (true)
  172. {
  173. context = m_httpListener.GetContext();
  174. ThreadPool.QueueUserWorkItem(new WaitCallback(HandleRequest), context);
  175. }
  176. }
  177. catch (Exception e)
  178. {
  179. MainLog.Instance.WriteLine(LogPriority.MEDIUM, e.Message);
  180. }
  181. }
  182. public void RemoveStreamHandler(string httpMethod, string path)
  183. {
  184. m_streamHandlers.Remove(GetHandlerKey(httpMethod, path));
  185. }
  186. }
  187. }