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