aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Framework/Servers/BaseHttpServer.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Framework/Servers/BaseHttpServer.cs')
-rw-r--r--OpenSim/Framework/Servers/BaseHttpServer.cs224
1 files changed, 224 insertions, 0 deletions
diff --git a/OpenSim/Framework/Servers/BaseHttpServer.cs b/OpenSim/Framework/Servers/BaseHttpServer.cs
new file mode 100644
index 0000000..f790477
--- /dev/null
+++ b/OpenSim/Framework/Servers/BaseHttpServer.cs
@@ -0,0 +1,224 @@
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*/
28using System;
29using System.Collections;
30using System.Collections.Generic;
31using System.IO;
32using System.Net;
33using System.Text;
34using System.Text.RegularExpressions;
35using System.Threading;
36using Nwc.XmlRpc;
37using OpenSim.Framework.Console;
38
39namespace OpenSim.Framework.Servers
40{
41 public class BaseHttpServer
42 {
43 protected Thread m_workerThread;
44 protected HttpListener m_httpListener;
45 protected Dictionary<string, XmlRpcMethod> m_rpcHandlers = new Dictionary<string, XmlRpcMethod>();
46 protected Dictionary<string, IStreamHandler> m_streamHandlers = new Dictionary<string, IStreamHandler>();
47 protected int m_port;
48 protected bool m_firstcaps = true;
49
50 public BaseHttpServer(int port)
51 {
52 m_port = port;
53 }
54
55 public void AddStreamHandler( IStreamHandler handler)
56 {
57 string httpMethod = handler.HttpMethod;
58 string path = handler.Path;
59
60 string handlerKey = GetHandlerKey(httpMethod, path);
61 m_streamHandlers.Add(handlerKey, handler);
62 }
63
64 private static string GetHandlerKey(string httpMethod, string path)
65 {
66 return httpMethod + ":" + path;
67 }
68
69 public bool AddXmlRPCHandler(string method, XmlRpcMethod handler)
70 {
71 if (!this.m_rpcHandlers.ContainsKey(method))
72 {
73 this.m_rpcHandlers.Add(method, handler);
74 return true;
75 }
76
77 //must already have a handler for that path so return false
78 return false;
79 }
80
81
82 public virtual void HandleRequest(Object stateinfo)
83 {
84 HttpListenerContext context = (HttpListenerContext)stateinfo;
85
86 HttpListenerRequest request = context.Request;
87 HttpListenerResponse response = context.Response;
88
89 response.KeepAlive = false;
90 response.SendChunked = false;
91
92 string path = request.RawUrl;
93 string handlerKey = GetHandlerKey( request.HttpMethod, path );
94
95 IStreamHandler streamHandler;
96
97 if (TryGetStreamHandler( handlerKey, out streamHandler))
98 {
99 byte[] buffer = streamHandler.Handle(path, request.InputStream);
100 request.InputStream.Close();
101
102 response.ContentType = streamHandler.ContentType;
103 response.ContentLength64 = buffer.LongLength;
104 response.OutputStream.Write(buffer, 0, buffer.Length);
105 response.OutputStream.Close();
106 }
107 else
108 {
109 HandleXmlRpcRequests(request, response);
110 }
111 }
112
113 private bool TryGetStreamHandler(string handlerKey, out IStreamHandler streamHandler)
114 {
115 string bestMatch = null;
116
117 foreach (string pattern in m_streamHandlers.Keys)
118 {
119 if (handlerKey.StartsWith(pattern))
120 {
121 if (String.IsNullOrEmpty(bestMatch) || pattern.Length > bestMatch.Length)
122 {
123 bestMatch = pattern;
124 }
125 }
126 }
127
128 if (String.IsNullOrEmpty(bestMatch))
129 {
130 streamHandler = null;
131 return false;
132 }
133 else
134 {
135 streamHandler = m_streamHandlers[bestMatch];
136 return true;
137 }
138 }
139
140 private void HandleXmlRpcRequests(HttpListenerRequest request, HttpListenerResponse response)
141 {
142 Stream requestStream = request.InputStream;
143
144 Encoding encoding = Encoding.UTF8;
145 StreamReader reader = new StreamReader(requestStream, encoding);
146
147 string requestBody = reader.ReadToEnd();
148 reader.Close();
149 requestStream.Close();
150
151 XmlRpcRequest xmlRprcRequest = (XmlRpcRequest)(new XmlRpcRequestDeserializer()).Deserialize(requestBody);
152
153 string methodName = xmlRprcRequest.MethodName;
154
155 XmlRpcResponse xmlRpcResponse;
156
157 XmlRpcMethod method;
158 if (this.m_rpcHandlers.TryGetValue(methodName, out method))
159 {
160 xmlRpcResponse = method(xmlRprcRequest);
161 }
162 else
163 {
164 xmlRpcResponse = new XmlRpcResponse();
165 Hashtable unknownMethodError = new Hashtable();
166 unknownMethodError["reason"] = "XmlRequest"; ;
167 unknownMethodError["message"] = "Unknown Rpc Request ["+methodName+"]";
168 unknownMethodError["login"] = "false";
169 xmlRpcResponse.Value = unknownMethodError;
170 }
171
172 response.AddHeader("Content-type", "text/xml");
173
174 string responseString = XmlRpcResponseSerializer.Singleton.Serialize(xmlRpcResponse);
175
176 byte[] buffer = Encoding.UTF8.GetBytes(responseString);
177
178 response.SendChunked = false;
179 response.ContentLength64 = buffer.Length;
180 response.ContentEncoding = Encoding.UTF8;
181
182 response.OutputStream.Write(buffer, 0, buffer.Length);
183 response.OutputStream.Close();
184 }
185
186 public void Start()
187 {
188 MainLog.Instance.WriteLine(LogPriority.LOW, "BaseHttpServer.cs: Starting up HTTP Server");
189
190 m_workerThread = new Thread(new ThreadStart(StartHTTP));
191 m_workerThread.IsBackground = true;
192 m_workerThread.Start();
193 }
194
195 private void StartHTTP()
196 {
197 try
198 {
199 MainLog.Instance.WriteLine(LogPriority.LOW, "BaseHttpServer.cs: StartHTTP() - Spawned main thread OK");
200 m_httpListener = new HttpListener();
201
202 m_httpListener.Prefixes.Add("http://+:" + m_port + "/");
203 m_httpListener.Start();
204
205 HttpListenerContext context;
206 while (true)
207 {
208 context = m_httpListener.GetContext();
209 ThreadPool.QueueUserWorkItem(new WaitCallback(HandleRequest), context);
210 }
211 }
212 catch (Exception e)
213 {
214 MainLog.Instance.WriteLine(LogPriority.MEDIUM, e.Message);
215 }
216 }
217
218
219 public void RemoveStreamHandler(string httpMethod, string path)
220 {
221 m_streamHandlers.Remove(GetHandlerKey(httpMethod, path));
222 }
223 }
224}