BaseHttpServer.cs 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Net;
  4. using System.Text;
  5. using System.Text.RegularExpressions;
  6. using System.Threading;
  7. //using OpenSim.CAPS;
  8. using Nwc.XmlRpc;
  9. using System.Collections;
  10. namespace OpenSim.Servers
  11. {
  12. public class BaseHttpServer
  13. {
  14. protected Thread m_workerThread;
  15. protected HttpListener m_httpListener;
  16. protected Dictionary<string, RestMethod> m_restHandlers = new Dictionary<string, RestMethod>();
  17. protected Dictionary<string, XmlRpcMethod> m_rpcHandlers = new Dictionary<string, XmlRpcMethod>();
  18. protected int m_port;
  19. public BaseHttpServer(int port)
  20. {
  21. m_port = port;
  22. }
  23. public bool AddRestHandler(string method, string path, RestMethod handler)
  24. {
  25. string methodKey = String.Format("{0}: {1}", method, path);
  26. if (!this.m_restHandlers.ContainsKey(methodKey))
  27. {
  28. this.m_restHandlers.Add(methodKey, handler);
  29. return true;
  30. }
  31. //must already have a handler for that path so return false
  32. return false;
  33. }
  34. public bool AddXmlRPCHandler(string method, XmlRpcMethod handler)
  35. {
  36. if (!this.m_rpcHandlers.ContainsKey(method))
  37. {
  38. this.m_rpcHandlers.Add(method, handler);
  39. return true;
  40. }
  41. //must already have a handler for that path so return false
  42. return false;
  43. }
  44. protected virtual string ProcessXMLRPCMethod(string methodName, XmlRpcRequest request)
  45. {
  46. XmlRpcResponse response;
  47. XmlRpcMethod method;
  48. if( this.m_rpcHandlers.TryGetValue( methodName, out method ) )
  49. {
  50. response = method(request);
  51. }
  52. else
  53. {
  54. response = new XmlRpcResponse();
  55. Hashtable unknownMethodError = new Hashtable();
  56. unknownMethodError["reason"] = "XmlRequest"; ;
  57. unknownMethodError["message"] = "Unknown Rpc request";
  58. unknownMethodError["login"] = "false";
  59. response.Value = unknownMethodError;
  60. }
  61. return XmlRpcResponseSerializer.Singleton.Serialize(response);
  62. }
  63. protected virtual string ParseREST(string request, string path, string method)
  64. {
  65. string response;
  66. RestMethod handler;
  67. string requestKey = String.Format("{0}: {1}", method, path);
  68. string bestMatch = String.Empty;
  69. foreach( string currentKey in m_restHandlers.Keys )
  70. {
  71. if( requestKey.StartsWith( currentKey ))
  72. {
  73. if(currentKey.Length > bestMatch.Length )
  74. {
  75. bestMatch = currentKey;
  76. }
  77. }
  78. }
  79. if (m_restHandlers.TryGetValue(bestMatch, out handler))
  80. {
  81. response = handler(request, path);
  82. }
  83. else
  84. {
  85. response = String.Empty;
  86. }
  87. return response;
  88. }
  89. protected virtual string ParseLLSDXML(string requestBody)
  90. {
  91. // dummy function for now - IMPLEMENT ME!
  92. return "";
  93. }
  94. protected virtual string ParseXMLRPC(string requestBody)
  95. {
  96. string responseString = String.Empty;
  97. try
  98. {
  99. XmlRpcRequest request = (XmlRpcRequest)(new XmlRpcRequestDeserializer()).Deserialize(requestBody);
  100. string methodName = request.MethodName;
  101. responseString = ProcessXMLRPCMethod(methodName, request );
  102. }
  103. catch (Exception e)
  104. {
  105. Console.WriteLine(e.ToString());
  106. }
  107. return responseString;
  108. }
  109. public virtual void HandleRequest(Object stateinfo)
  110. {
  111. HttpListenerContext context = (HttpListenerContext)stateinfo;
  112. HttpListenerRequest request = context.Request;
  113. HttpListenerResponse response = context.Response;
  114. response.KeepAlive = false;
  115. response.SendChunked = false;
  116. System.IO.Stream body = request.InputStream;
  117. System.Text.Encoding encoding = System.Text.Encoding.UTF8;
  118. System.IO.StreamReader reader = new System.IO.StreamReader(body, encoding);
  119. string requestBody = reader.ReadToEnd();
  120. body.Close();
  121. reader.Close();
  122. //Console.WriteLine(request.HttpMethod + " " + request.RawUrl + " Http/" + request.ProtocolVersion.ToString() + " content type: " + request.ContentType);
  123. //Console.WriteLine(requestBody);
  124. string responseString = "";
  125. switch (request.ContentType)
  126. {
  127. case "text/xml":
  128. // must be XML-RPC, so pass to the XML-RPC parser
  129. responseString = ParseXMLRPC(requestBody);
  130. responseString = Regex.Replace(responseString, "utf-16", "utf-8");
  131. response.AddHeader("Content-type", "text/xml");
  132. break;
  133. case "application/xml":
  134. // probably LLSD we hope, otherwise it should be ignored by the parser
  135. responseString = ParseLLSDXML(requestBody);
  136. response.AddHeader("Content-type", "application/xml");
  137. break;
  138. case "application/x-www-form-urlencoded":
  139. // a form data POST so send to the REST parser
  140. responseString = ParseREST(requestBody, request.RawUrl, request.HttpMethod);
  141. response.AddHeader("Content-type", "text/html");
  142. break;
  143. case null:
  144. // must be REST or invalid crap, so pass to the REST parser
  145. responseString = ParseREST(requestBody, request.RawUrl, request.HttpMethod);
  146. response.AddHeader("Content-type", "text/html");
  147. break;
  148. }
  149. byte[] buffer = System.Text.Encoding.UTF8.GetBytes(responseString);
  150. System.IO.Stream output = response.OutputStream;
  151. response.SendChunked = false;
  152. response.ContentLength64 = buffer.Length;
  153. output.Write(buffer, 0, buffer.Length);
  154. output.Close();
  155. }
  156. public void Start()
  157. {
  158. OpenSim.Framework.Console.MainConsole.Instance.WriteLine("BaseHttpServer.cs: Starting up HTTP Server");
  159. m_workerThread = new Thread(new ThreadStart(StartHTTP));
  160. m_workerThread.IsBackground = true;
  161. m_workerThread.Start();
  162. }
  163. private void StartHTTP()
  164. {
  165. try
  166. {
  167. OpenSim.Framework.Console.MainConsole.Instance.WriteLine("BaseHttpServer.cs: StartHTTP() - Spawned main thread OK");
  168. m_httpListener = new HttpListener();
  169. m_httpListener.Prefixes.Add("http://+:" + m_port + "/");
  170. m_httpListener.Start();
  171. HttpListenerContext context;
  172. while (true)
  173. {
  174. context = m_httpListener.GetContext();
  175. ThreadPool.QueueUserWorkItem(new WaitCallback(HandleRequest), context);
  176. }
  177. }
  178. catch (Exception e)
  179. {
  180. OpenSim.Framework.Console.MainConsole.Instance.WriteLine(e.Message);
  181. }
  182. }
  183. }
  184. }