aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs')
-rw-r--r--OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs226
1 files changed, 184 insertions, 42 deletions
diff --git a/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs b/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs
index 92be3a3..da2b860 100644
--- a/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs
+++ b/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs
@@ -32,6 +32,7 @@ using System.Collections.Specialized;
32using System.IO; 32using System.IO;
33using System.Net; 33using System.Net;
34using System.Net.Sockets; 34using System.Net.Sockets;
35using System.Net.Security;
35using System.Security.Cryptography.X509Certificates; 36using System.Security.Cryptography.X509Certificates;
36using System.Reflection; 37using System.Reflection;
37using System.Globalization; 38using System.Globalization;
@@ -43,10 +44,11 @@ using log4net;
43using Nwc.XmlRpc; 44using Nwc.XmlRpc;
44using OpenMetaverse.StructuredData; 45using OpenMetaverse.StructuredData;
45using CoolHTTPListener = HttpServer.HttpListener; 46using CoolHTTPListener = HttpServer.HttpListener;
46using HttpListener=System.Net.HttpListener; 47using HttpListener = System.Net.HttpListener;
47using LogPrio=HttpServer.LogPrio; 48using LogPrio = HttpServer.LogPrio;
48using OpenSim.Framework.Monitoring; 49using OpenSim.Framework.Monitoring;
49using System.IO.Compression; 50using System.IO.Compression;
51using System.Security.Cryptography;
50 52
51namespace OpenSim.Framework.Servers.HttpServer 53namespace OpenSim.Framework.Servers.HttpServer
52{ 54{
@@ -107,19 +109,26 @@ namespace OpenSim.Framework.Servers.HttpServer
107 new Dictionary<string, WebSocketRequestDelegate>(); 109 new Dictionary<string, WebSocketRequestDelegate>();
108 110
109 protected uint m_port; 111 protected uint m_port;
110 protected uint m_sslport;
111 protected bool m_ssl; 112 protected bool m_ssl;
112 private X509Certificate2 m_cert; 113 private X509Certificate2 m_cert;
113 protected bool m_firstcaps = true;
114 protected string m_SSLCommonName = ""; 114 protected string m_SSLCommonName = "";
115 protected List<string> m_certNames = new List<string>();
116 protected List<string> m_certIPs = new List<string>();
117 protected string m_certCN= "";
118 protected RemoteCertificateValidationCallback m_certificateValidationCallback = null;
115 119
116 protected IPAddress m_listenIPAddress = IPAddress.Any; 120 protected IPAddress m_listenIPAddress = IPAddress.Any;
117 121
118 public PollServiceRequestManager PollServiceRequestManager { get; private set; } 122 public PollServiceRequestManager PollServiceRequestManager { get; private set; }
119 123
124 public string Protocol
125 {
126 get { return m_ssl ? "https://" : "http://"; }
127 }
128
120 public uint SSLPort 129 public uint SSLPort
121 { 130 {
122 get { return m_sslport; } 131 get { return m_port; }
123 } 132 }
124 133
125 public string SSLCommonName 134 public string SSLCommonName
@@ -148,27 +157,151 @@ namespace OpenSim.Framework.Servers.HttpServer
148 m_port = port; 157 m_port = port;
149 } 158 }
150 159
151 public BaseHttpServer(uint port, bool ssl) : this (port) 160 private void load_cert(string CPath, string CPass)
152 { 161 {
153 m_ssl = ssl; 162 try
163 {
164 m_cert = new X509Certificate2(CPath, CPass);
165 X509Extension ext = m_cert.Extensions["2.5.29.17"];
166 if(ext != null)
167 {
168 AsnEncodedData asndata = new AsnEncodedData(ext.Oid, ext.RawData);
169 string datastr = asndata.Format(true);
170 string[] lines = datastr.Split(new char[] {'\n','\r'});
171 foreach(string s in lines)
172 {
173 if(String.IsNullOrEmpty(s))
174 continue;
175 string[] parts = s.Split(new char[] {'='});
176 if(String.IsNullOrEmpty(parts[0]))
177 continue;
178 string entryName = parts[0].Replace(" ","");
179 if(entryName == "DNSName")
180 m_certNames.Add(parts[1]);
181 else if(entryName == "IPAddress")
182 m_certIPs.Add(parts[1]);
183 }
184 }
185 m_certCN = m_cert.GetNameInfo(X509NameType.SimpleName, false);
186 }
187 catch
188 {
189 throw new Exception("SSL cert load error");
190 }
154 } 191 }
155 192
156 public BaseHttpServer(uint port, bool ssl, uint sslport, string CN) : this (port, ssl) 193 public BaseHttpServer(uint port, bool ssl, string CN, string CPath, string CPass)
157 { 194 {
158 if (m_ssl) 195 m_port = port;
196 if (ssl)
159 { 197 {
160 m_sslport = sslport; 198 if(string.IsNullOrEmpty(CPath))
199 throw new Exception("invalid main http server cert path");
200
201 if(Uri.CheckHostName(CN) == UriHostNameType.Unknown)
202 throw new Exception("invalid main http server CN (ExternalHostName)");
203
204 m_certNames.Clear();
205 m_certIPs.Clear();
206 m_certCN= "";
207
208 m_ssl = true;
209 load_cert(CPath, CPass);
210
211 if(!CheckSSLCertHost(CN))
212 throw new Exception("invalid main http server CN (ExternalHostName)");
213
214 m_SSLCommonName = CN;
215
216 if(m_cert.Issuer == m_cert.Subject )
217 m_log.Warn("Self signed certificate. Clients need to allow this (some viewers debug option NoVerifySSLcert must be set to true");
161 } 218 }
219 else
220 m_ssl = false;
162 } 221 }
163 222
164 public BaseHttpServer(uint port, bool ssl, string CPath, string CPass) : this (port, ssl) 223 public BaseHttpServer(uint port, bool ssl, string CPath, string CPass)
165 { 224 {
166 if (m_ssl) 225 m_port = port;
226 if (ssl)
167 { 227 {
168 m_cert = new X509Certificate2(CPath, CPass); 228 load_cert(CPath, CPass);
229 if(m_cert.Issuer == m_cert.Subject )
230 m_log.Warn("Self signed certificate. Http clients need to allow this");
231 m_ssl = true;
232 }
233 else
234 m_ssl = false;
235 }
236
237 static bool MatchDNS (string hostname, string dns)
238 {
239 int indx = dns.IndexOf ('*');
240 if (indx == -1)
241 return (String.Compare(hostname, dns, true, CultureInfo.InvariantCulture) == 0);
242
243 int dnslen = dns.Length;
244 dnslen--;
245 if(indx == dnslen)
246 return true; // just * ?
247
248 if(indx > dnslen - 2)
249 return false; // 2 short ?
250
251 if (dns[indx + 1] != '.')
252 return false;
253
254 int indx2 = dns.IndexOf ('*', indx + 1);
255 if (indx2 != -1)
256 return false; // there can only be one;
257
258 string end = dns.Substring(indx + 1);
259 int hostlen = hostname.Length;
260 int endlen = end.Length;
261 int length = hostlen - endlen;
262 if (length <= 0)
263 return false;
264
265 if (String.Compare(hostname, length, end, 0, endlen, true, CultureInfo.InvariantCulture) != 0)
266 return false;
267
268 if (indx == 0)
269 {
270 indx2 = hostname.IndexOf ('.');
271 return ((indx2 == -1) || (indx2 >= length));
272 }
273
274 string start = dns.Substring (0, indx);
275 return (String.Compare (hostname, 0, start, 0, start.Length, true, CultureInfo.InvariantCulture) == 0);
276 }
277
278 public bool CheckSSLCertHost(string hostname)
279 {
280 UriHostNameType htype = Uri.CheckHostName(hostname);
281
282 if(htype == UriHostNameType.Unknown || htype == UriHostNameType.Basic)
283 return false;
284 if(htype == UriHostNameType.Dns)
285 {
286 foreach(string name in m_certNames)
287 {
288 if(MatchDNS(hostname, name))
289 return true;
290 }
291 if(MatchDNS(hostname, m_certCN))
292 return true;
293 }
294 else
295 {
296 foreach(string ip in m_certIPs)
297 {
298 if (String.Compare(hostname, ip, true, CultureInfo.InvariantCulture) != 0)
299 return true;
300 }
169 } 301 }
170 }
171 302
303 return false;
304 }
172 /// <summary> 305 /// <summary>
173 /// Add a stream handler to the http server. If the handler already exists, then nothing happens. 306 /// Add a stream handler to the http server. If the handler already exists, then nothing happens.
174 /// </summary> 307 /// </summary>
@@ -396,12 +529,9 @@ namespace OpenSim.Framework.Servers.HttpServer
396 if (psEvArgs.Request != null) 529 if (psEvArgs.Request != null)
397 { 530 {
398 OSHttpRequest req = new OSHttpRequest(context, request); 531 OSHttpRequest req = new OSHttpRequest(context, request);
399
400 Stream requestStream = req.InputStream;
401
402 string requestBody; 532 string requestBody;
403 Encoding encoding = Encoding.UTF8; 533 Encoding encoding = Encoding.UTF8;
404 using(StreamReader reader = new StreamReader(requestStream, encoding)) 534 using(StreamReader reader = new StreamReader(req.InputStream, encoding))
405 requestBody = reader.ReadToEnd(); 535 requestBody = reader.ReadToEnd();
406 536
407 Hashtable keysvals = new Hashtable(); 537 Hashtable keysvals = new Hashtable();
@@ -460,7 +590,7 @@ namespace OpenSim.Framework.Servers.HttpServer
460 } 590 }
461 591
462 OSHttpResponse resp = new OSHttpResponse(new HttpResponse(context, request),context); 592 OSHttpResponse resp = new OSHttpResponse(new HttpResponse(context, request),context);
463 resp.ReuseContext = true; 593// resp.ReuseContext = true;
464// resp.ReuseContext = false; 594// resp.ReuseContext = false;
465 HandleRequest(req, resp); 595 HandleRequest(req, resp);
466 596
@@ -496,6 +626,8 @@ namespace OpenSim.Framework.Servers.HttpServer
496 byte[] buffer500 = SendHTML500(response); 626 byte[] buffer500 = SendHTML500(response);
497 response.OutputStream.Write(buffer500, 0, buffer500.Length); 627 response.OutputStream.Write(buffer500, 0, buffer500.Length);
498 response.Send(); 628 response.Send();
629 if(request.InputStream.CanRead)
630 request.InputStream.Close();
499 } 631 }
500 catch 632 catch
501 { 633 {
@@ -540,7 +672,6 @@ namespace OpenSim.Framework.Servers.HttpServer
540// } 672// }
541// } 673// }
542 674
543 //response.KeepAlive = true;
544 response.SendChunked = false; 675 response.SendChunked = false;
545 676
546 string path = request.RawUrl; 677 string path = request.RawUrl;
@@ -564,11 +695,10 @@ namespace OpenSim.Framework.Servers.HttpServer
564 { 695 {
565 //m_log.Debug("[BASE HTTP SERVER]: Found Caps based HTTP Handler"); 696 //m_log.Debug("[BASE HTTP SERVER]: Found Caps based HTTP Handler");
566 IGenericHTTPHandler HTTPRequestHandler = requestHandler as IGenericHTTPHandler; 697 IGenericHTTPHandler HTTPRequestHandler = requestHandler as IGenericHTTPHandler;
567 Stream requestStream = request.InputStream;
568 698
569 string requestBody; 699 string requestBody;
570 Encoding encoding = Encoding.UTF8; 700 Encoding encoding = Encoding.UTF8;
571 using(StreamReader reader = new StreamReader(requestStream, encoding)) 701 using(StreamReader reader = new StreamReader(request.InputStream, encoding))
572 requestBody = reader.ReadToEnd(); 702 requestBody = reader.ReadToEnd();
573 703
574 Hashtable keysvals = new Hashtable(); 704 Hashtable keysvals = new Hashtable();
@@ -609,7 +739,6 @@ namespace OpenSim.Framework.Servers.HttpServer
609 else 739 else
610 { 740 {
611 IStreamHandler streamHandler = (IStreamHandler)requestHandler; 741 IStreamHandler streamHandler = (IStreamHandler)requestHandler;
612
613 using (MemoryStream memoryStream = new MemoryStream()) 742 using (MemoryStream memoryStream = new MemoryStream())
614 { 743 {
615 streamHandler.Handle(path, request.InputStream, memoryStream, request, response); 744 streamHandler.Handle(path, request.InputStream, memoryStream, request, response);
@@ -720,10 +849,6 @@ namespace OpenSim.Framework.Servers.HttpServer
720 requestEndTick = Environment.TickCount; 849 requestEndTick = Environment.TickCount;
721 850
722 response.Send(); 851 response.Send();
723
724 //response.OutputStream.Close();
725
726 //response.FreeContext();
727 } 852 }
728 catch (SocketException e) 853 catch (SocketException e)
729 { 854 {
@@ -755,6 +880,9 @@ namespace OpenSim.Framework.Servers.HttpServer
755 } 880 }
756 finally 881 finally
757 { 882 {
883 if(request.InputStream.CanRead)
884 request.InputStream.Close();
885
758 // Every month or so this will wrap and give bad numbers, not really a problem 886 // Every month or so this will wrap and give bad numbers, not really a problem
759 // since its just for reporting 887 // since its just for reporting
760 int tickdiff = requestEndTick - requestStartTick; 888 int tickdiff = requestEndTick - requestStartTick;
@@ -1008,12 +1136,13 @@ namespace OpenSim.Framework.Servers.HttpServer
1008 using (StreamReader reader = new StreamReader(requestStream, Encoding.UTF8)) 1136 using (StreamReader reader = new StreamReader(requestStream, Encoding.UTF8))
1009 requestBody = reader.ReadToEnd(); 1137 requestBody = reader.ReadToEnd();
1010 1138
1011 } 1139 }
1012 finally 1140 finally
1013 { 1141 {
1014 if (innerStream != null) 1142 if (innerStream != null && innerStream.CanRead)
1015 innerStream.Dispose(); 1143 innerStream.Dispose();
1016 requestStream.Dispose(); 1144 if (requestStream.CanRead)
1145 requestStream.Dispose();
1017 } 1146 }
1018 1147
1019 //m_log.Debug(requestBody); 1148 //m_log.Debug(requestBody);
@@ -1094,6 +1223,17 @@ namespace OpenSim.Framework.Servers.HttpServer
1094 1223
1095 if (gridproxy) 1224 if (gridproxy)
1096 xmlRprcRequest.Params.Add("gridproxy"); // Param[4] 1225 xmlRprcRequest.Params.Add("gridproxy"); // Param[4]
1226
1227 // reserve this for
1228 // ... by Fumi.Iseki for DTLNSLMoneyServer
1229 // BUT make its presence possible to detect/parse
1230 string rcn = request.IHttpClientContext.SSLCommonName;
1231 if(!string.IsNullOrWhiteSpace(rcn))
1232 {
1233 rcn = "SSLCN:" + rcn;
1234 xmlRprcRequest.Params.Add(rcn); // Param[4] or Param[5]
1235 }
1236
1097 try 1237 try
1098 { 1238 {
1099 xmlRpcResponse = method(xmlRprcRequest, request.RemoteIPEndPoint); 1239 xmlRpcResponse = method(xmlRprcRequest, request.RemoteIPEndPoint);
@@ -1265,7 +1405,6 @@ namespace OpenSim.Framework.Servers.HttpServer
1265 requestBody= reader.ReadToEnd(); 1405 requestBody= reader.ReadToEnd();
1266 1406
1267 //m_log.DebugFormat("[OGP]: {0}:{1}", request.RawUrl, requestBody); 1407 //m_log.DebugFormat("[OGP]: {0}:{1}", request.RawUrl, requestBody);
1268 response.KeepAlive = true;
1269 1408
1270 OSD llsdRequest = null; 1409 OSD llsdRequest = null;
1271 OSD llsdResponse = null; 1410 OSD llsdResponse = null;
@@ -1793,7 +1932,7 @@ namespace OpenSim.Framework.Servers.HttpServer
1793*/ 1932*/
1794 // disable this things 1933 // disable this things
1795 response.KeepAlive = false; 1934 response.KeepAlive = false;
1796 response.ReuseContext = false; 1935 // response.ReuseContext = false;
1797 1936
1798 // Cross-Origin Resource Sharing with simple requests 1937 // Cross-Origin Resource Sharing with simple requests
1799 if (responsedata.ContainsKey("access_control_allow_origin")) 1938 if (responsedata.ContainsKey("access_control_allow_origin"))
@@ -1895,7 +2034,7 @@ namespace OpenSim.Framework.Servers.HttpServer
1895 2034
1896 public void Start() 2035 public void Start()
1897 { 2036 {
1898 Start(true); 2037 Start(true,true);
1899 } 2038 }
1900 2039
1901 /// <summary> 2040 /// <summary>
@@ -1905,7 +2044,7 @@ namespace OpenSim.Framework.Servers.HttpServer
1905 /// If true then poll responses are performed asynchronsly. 2044 /// If true then poll responses are performed asynchronsly.
1906 /// Option exists to allow regression tests to perform processing synchronously. 2045 /// Option exists to allow regression tests to perform processing synchronously.
1907 /// </param> 2046 /// </param>
1908 public void Start(bool performPollResponsesAsync) 2047 public void Start(bool performPollResponsesAsync, bool runPool)
1909 { 2048 {
1910 m_log.InfoFormat( 2049 m_log.InfoFormat(
1911 "[BASE HTTP SERVER]: Starting {0} server on port {1}", UseSSL ? "HTTPS" : "HTTP", Port); 2050 "[BASE HTTP SERVER]: Starting {0} server on port {1}", UseSSL ? "HTTPS" : "HTTP", Port);
@@ -1934,6 +2073,8 @@ namespace OpenSim.Framework.Servers.HttpServer
1934 //m_httpListener.Prefixes.Add("https://+:" + (m_sslport) + "/"); 2073 //m_httpListener.Prefixes.Add("https://+:" + (m_sslport) + "/");
1935 //m_httpListener.Prefixes.Add("http://+:" + m_port + "/"); 2074 //m_httpListener.Prefixes.Add("http://+:" + m_port + "/");
1936 m_httpListener2 = CoolHTTPListener.Create(IPAddress.Any, (int)m_port, m_cert); 2075 m_httpListener2 = CoolHTTPListener.Create(IPAddress.Any, (int)m_port, m_cert);
2076 if(m_certificateValidationCallback != null)
2077 m_httpListener2.CertificateValidationCallback = m_certificateValidationCallback;
1937 m_httpListener2.ExceptionThrown += httpServerException; 2078 m_httpListener2.ExceptionThrown += httpServerException;
1938 m_httpListener2.LogWriter = httpserverlog; 2079 m_httpListener2.LogWriter = httpserverlog;
1939 } 2080 }
@@ -1943,9 +2084,11 @@ namespace OpenSim.Framework.Servers.HttpServer
1943 m_httpListener2.Start(64); 2084 m_httpListener2.Start(64);
1944 2085
1945 // Long Poll Service Manager with 3 worker threads a 25 second timeout for no events 2086 // Long Poll Service Manager with 3 worker threads a 25 second timeout for no events
1946 2087 if(runPool)
1947 PollServiceRequestManager = new PollServiceRequestManager(this, performPollResponsesAsync, 2, 25000); 2088 {
1948 PollServiceRequestManager.Start(); 2089 PollServiceRequestManager = new PollServiceRequestManager(this, performPollResponsesAsync, 2, 25000);
2090 PollServiceRequestManager.Start();
2091 }
1949 2092
1950 HTTPDRunning = true; 2093 HTTPDRunning = true;
1951 2094
@@ -1959,7 +2102,7 @@ namespace OpenSim.Framework.Servers.HttpServer
1959 catch (Exception e) 2102 catch (Exception e)
1960 { 2103 {
1961 m_log.Error("[BASE HTTP SERVER]: Error - " + e.Message); 2104 m_log.Error("[BASE HTTP SERVER]: Error - " + e.Message);
1962 m_log.Error("[BASE HTTP SERVER]: Tip: Do you have permission to listen on port " + m_port + ", " + m_sslport + "?"); 2105 m_log.Error("[BASE HTTP SERVER]: Tip: Do you have permission to listen on port " + m_port + "?");
1963 2106
1964 // We want this exception to halt the entire server since in current configurations we aren't too 2107 // We want this exception to halt the entire server since in current configurations we aren't too
1965 // useful without inbound HTTP. 2108 // useful without inbound HTTP.
@@ -2124,10 +2267,9 @@ namespace OpenSim.Framework.Servers.HttpServer
2124 string file = Path.Combine(".", "http_500.html"); 2267 string file = Path.Combine(".", "http_500.html");
2125 if (!File.Exists(file)) 2268 if (!File.Exists(file))
2126 return getDefaultHTTP500(); 2269 return getDefaultHTTP500();
2127 2270 string result;
2128 StreamReader sr = File.OpenText(file); 2271 using(StreamReader sr = File.OpenText(file))
2129 string result = sr.ReadToEnd(); 2272 result = sr.ReadToEnd();
2130 sr.Close();
2131 return result; 2273 return result;
2132 } 2274 }
2133 2275