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.cs261
1 files changed, 197 insertions, 64 deletions
diff --git a/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs b/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs
index fb92b92..516604a 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,14 +529,10 @@ 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 532 string requestBody = String.Empty;
400 Stream requestStream = req.InputStream;
401
402 Encoding encoding = Encoding.UTF8; 533 Encoding encoding = Encoding.UTF8;
403 StreamReader reader = new StreamReader(requestStream, encoding); 534 using(StreamReader reader = new StreamReader(req.InputStream, encoding))
404 535 requestBody = reader.ReadToEnd();
405 string requestBody = reader.ReadToEnd();
406 reader.Close();
407 536
408 Hashtable keysvals = new Hashtable(); 537 Hashtable keysvals = new Hashtable();
409 Hashtable headervals = new Hashtable(); 538 Hashtable headervals = new Hashtable();
@@ -461,7 +590,7 @@ namespace OpenSim.Framework.Servers.HttpServer
461 } 590 }
462 591
463 OSHttpResponse resp = new OSHttpResponse(new HttpResponse(context, request),context); 592 OSHttpResponse resp = new OSHttpResponse(new HttpResponse(context, request),context);
464 resp.ReuseContext = true; 593// resp.ReuseContext = true;
465// resp.ReuseContext = false; 594// resp.ReuseContext = false;
466 HandleRequest(req, resp); 595 HandleRequest(req, resp);
467 596
@@ -497,6 +626,8 @@ namespace OpenSim.Framework.Servers.HttpServer
497 byte[] buffer500 = SendHTML500(response); 626 byte[] buffer500 = SendHTML500(response);
498 response.OutputStream.Write(buffer500, 0, buffer500.Length); 627 response.OutputStream.Write(buffer500, 0, buffer500.Length);
499 response.Send(); 628 response.Send();
629 if(request.InputStream.CanRead)
630 request.InputStream.Close();
500 } 631 }
501 catch 632 catch
502 { 633 {
@@ -541,7 +672,6 @@ namespace OpenSim.Framework.Servers.HttpServer
541// } 672// }
542// } 673// }
543 674
544 //response.KeepAlive = true;
545 response.SendChunked = false; 675 response.SendChunked = false;
546 676
547 string path = request.RawUrl; 677 string path = request.RawUrl;
@@ -565,15 +695,10 @@ namespace OpenSim.Framework.Servers.HttpServer
565 { 695 {
566 //m_log.Debug("[BASE HTTP SERVER]: Found Caps based HTTP Handler"); 696 //m_log.Debug("[BASE HTTP SERVER]: Found Caps based HTTP Handler");
567 IGenericHTTPHandler HTTPRequestHandler = requestHandler as IGenericHTTPHandler; 697 IGenericHTTPHandler HTTPRequestHandler = requestHandler as IGenericHTTPHandler;
568 Stream requestStream = request.InputStream; 698 string requestBody = String.Empty;
569
570 Encoding encoding = Encoding.UTF8; 699 Encoding encoding = Encoding.UTF8;
571 StreamReader reader = new StreamReader(requestStream, encoding); 700 using(StreamReader reader = new StreamReader(request.InputStream, encoding))
572 701 requestBody = reader.ReadToEnd();
573 string requestBody = reader.ReadToEnd();
574
575 reader.Close();
576 //requestStream.Close();
577 702
578 Hashtable keysvals = new Hashtable(); 703 Hashtable keysvals = new Hashtable();
579 Hashtable headervals = new Hashtable(); 704 Hashtable headervals = new Hashtable();
@@ -613,7 +738,6 @@ namespace OpenSim.Framework.Servers.HttpServer
613 else 738 else
614 { 739 {
615 IStreamHandler streamHandler = (IStreamHandler)requestHandler; 740 IStreamHandler streamHandler = (IStreamHandler)requestHandler;
616
617 using (MemoryStream memoryStream = new MemoryStream()) 741 using (MemoryStream memoryStream = new MemoryStream())
618 { 742 {
619 streamHandler.Handle(path, request.InputStream, memoryStream, request, response); 743 streamHandler.Handle(path, request.InputStream, memoryStream, request, response);
@@ -690,8 +814,6 @@ namespace OpenSim.Framework.Servers.HttpServer
690 } 814 }
691 } 815 }
692 816
693 request.InputStream.Close();
694
695 if (buffer != null) 817 if (buffer != null)
696 { 818 {
697 if (WebUtil.DebugLevel >= 5) 819 if (WebUtil.DebugLevel >= 5)
@@ -723,10 +845,6 @@ namespace OpenSim.Framework.Servers.HttpServer
723 requestEndTick = Environment.TickCount; 845 requestEndTick = Environment.TickCount;
724 846
725 response.Send(); 847 response.Send();
726
727 //response.OutputStream.Close();
728
729 //response.FreeContext();
730 } 848 }
731 catch (SocketException e) 849 catch (SocketException e)
732 { 850 {
@@ -758,6 +876,9 @@ namespace OpenSim.Framework.Servers.HttpServer
758 } 876 }
759 finally 877 finally
760 { 878 {
879 if(request.InputStream.CanRead)
880 request.InputStream.Close();
881
761 // Every month or so this will wrap and give bad numbers, not really a problem 882 // Every month or so this will wrap and give bad numbers, not really a problem
762 // since its just for reporting 883 // since its just for reporting
763 int tickdiff = requestEndTick - requestStartTick; 884 int tickdiff = requestEndTick - requestStartTick;
@@ -1015,9 +1136,10 @@ namespace OpenSim.Framework.Servers.HttpServer
1015 } 1136 }
1016 finally 1137 finally
1017 { 1138 {
1018 if (innerStream != null) 1139 if (innerStream != null && innerStream.CanRead)
1019 innerStream.Dispose(); 1140 innerStream.Dispose();
1020 requestStream.Dispose(); 1141 if (requestStream.CanRead)
1142 requestStream.Dispose();
1021 } 1143 }
1022 1144
1023 //m_log.Debug(requestBody); 1145 //m_log.Debug(requestBody);
@@ -1098,6 +1220,17 @@ namespace OpenSim.Framework.Servers.HttpServer
1098 1220
1099 if (gridproxy) 1221 if (gridproxy)
1100 xmlRprcRequest.Params.Add("gridproxy"); // Param[4] 1222 xmlRprcRequest.Params.Add("gridproxy"); // Param[4]
1223
1224 // reserve this for
1225 // ... by Fumi.Iseki for DTLNSLMoneyServer
1226 // BUT make its presence possible to detect/parse
1227 string rcn = request.IHttpClientContext.SSLCommonName;
1228 if(!string.IsNullOrWhiteSpace(rcn))
1229 {
1230 rcn = "SSLCN:" + rcn;
1231 xmlRprcRequest.Params.Add(rcn); // Param[4] or Param[5]
1232 }
1233
1101 try 1234 try
1102 { 1235 {
1103 xmlRpcResponse = method(xmlRprcRequest, request.RemoteIPEndPoint); 1236 xmlRpcResponse = method(xmlRprcRequest, request.RemoteIPEndPoint);
@@ -1263,15 +1396,15 @@ namespace OpenSim.Framework.Servers.HttpServer
1263 //m_log.Warn("[BASE HTTP SERVER]: We've figured out it's a LLSD Request"); 1396 //m_log.Warn("[BASE HTTP SERVER]: We've figured out it's a LLSD Request");
1264 Stream requestStream = request.InputStream; 1397 Stream requestStream = request.InputStream;
1265 1398
1399 string requestBody = string.Empty;
1266 Encoding encoding = Encoding.UTF8; 1400 Encoding encoding = Encoding.UTF8;
1267 StreamReader reader = new StreamReader(requestStream, encoding); 1401 using(StreamReader reader = new StreamReader(requestStream,encoding))
1402 requestBody = reader.ReadToEnd();
1268 1403
1269 string requestBody = reader.ReadToEnd(); 1404 if(requestStream.CanRead)
1270 reader.Close(); 1405 requestStream.Close();
1271 requestStream.Close();
1272 1406
1273 //m_log.DebugFormat("[OGP]: {0}:{1}", request.RawUrl, requestBody); 1407 //m_log.DebugFormat("[OGP]: {0}:{1}", request.RawUrl, requestBody);
1274 response.KeepAlive = true;
1275 1408
1276 OSD llsdRequest = null; 1409 OSD llsdRequest = null;
1277 OSD llsdResponse = null; 1410 OSD llsdResponse = null;
@@ -1592,15 +1725,12 @@ namespace OpenSim.Framework.Servers.HttpServer
1592 byte[] buffer; 1725 byte[] buffer;
1593 1726
1594 Stream requestStream = request.InputStream; 1727 Stream requestStream = request.InputStream;
1595 1728 string requestBody = string.Empty;
1596 Encoding encoding = Encoding.UTF8; 1729 Encoding encoding = Encoding.UTF8;
1597 StreamReader reader = new StreamReader(requestStream, encoding); 1730 using(StreamReader reader = new StreamReader(requestStream,encoding))
1598 1731 requestBody = reader.ReadToEnd();
1599 string requestBody = reader.ReadToEnd(); 1732 if(requestStream.CanRead)
1600 // avoid warning for now 1733 requestStream.Close();
1601 reader.ReadToEnd();
1602 reader.Close();
1603 requestStream.Close();
1604 1734
1605 Hashtable keysvals = new Hashtable(); 1735 Hashtable keysvals = new Hashtable();
1606 Hashtable headervals = new Hashtable(); 1736 Hashtable headervals = new Hashtable();
@@ -1804,7 +1934,7 @@ namespace OpenSim.Framework.Servers.HttpServer
1804*/ 1934*/
1805 // disable this things 1935 // disable this things
1806 response.KeepAlive = false; 1936 response.KeepAlive = false;
1807 response.ReuseContext = false; 1937 // response.ReuseContext = false;
1808 1938
1809 // Cross-Origin Resource Sharing with simple requests 1939 // Cross-Origin Resource Sharing with simple requests
1810 if (responsedata.ContainsKey("access_control_allow_origin")) 1940 if (responsedata.ContainsKey("access_control_allow_origin"))
@@ -1906,7 +2036,7 @@ namespace OpenSim.Framework.Servers.HttpServer
1906 2036
1907 public void Start() 2037 public void Start()
1908 { 2038 {
1909 Start(true); 2039 Start(true,true);
1910 } 2040 }
1911 2041
1912 /// <summary> 2042 /// <summary>
@@ -1916,7 +2046,7 @@ namespace OpenSim.Framework.Servers.HttpServer
1916 /// If true then poll responses are performed asynchronsly. 2046 /// If true then poll responses are performed asynchronsly.
1917 /// Option exists to allow regression tests to perform processing synchronously. 2047 /// Option exists to allow regression tests to perform processing synchronously.
1918 /// </param> 2048 /// </param>
1919 public void Start(bool performPollResponsesAsync) 2049 public void Start(bool performPollResponsesAsync, bool runPool)
1920 { 2050 {
1921 m_log.InfoFormat( 2051 m_log.InfoFormat(
1922 "[BASE HTTP SERVER]: Starting {0} server on port {1}", UseSSL ? "HTTPS" : "HTTP", Port); 2052 "[BASE HTTP SERVER]: Starting {0} server on port {1}", UseSSL ? "HTTPS" : "HTTP", Port);
@@ -1945,6 +2075,8 @@ namespace OpenSim.Framework.Servers.HttpServer
1945 //m_httpListener.Prefixes.Add("https://+:" + (m_sslport) + "/"); 2075 //m_httpListener.Prefixes.Add("https://+:" + (m_sslport) + "/");
1946 //m_httpListener.Prefixes.Add("http://+:" + m_port + "/"); 2076 //m_httpListener.Prefixes.Add("http://+:" + m_port + "/");
1947 m_httpListener2 = CoolHTTPListener.Create(IPAddress.Any, (int)m_port, m_cert); 2077 m_httpListener2 = CoolHTTPListener.Create(IPAddress.Any, (int)m_port, m_cert);
2078 if(m_certificateValidationCallback != null)
2079 m_httpListener2.CertificateValidationCallback = m_certificateValidationCallback;
1948 m_httpListener2.ExceptionThrown += httpServerException; 2080 m_httpListener2.ExceptionThrown += httpServerException;
1949 m_httpListener2.LogWriter = httpserverlog; 2081 m_httpListener2.LogWriter = httpserverlog;
1950 } 2082 }
@@ -1954,9 +2086,11 @@ namespace OpenSim.Framework.Servers.HttpServer
1954 m_httpListener2.Start(64); 2086 m_httpListener2.Start(64);
1955 2087
1956 // Long Poll Service Manager with 3 worker threads a 25 second timeout for no events 2088 // Long Poll Service Manager with 3 worker threads a 25 second timeout for no events
1957 2089 if(runPool)
1958 PollServiceRequestManager = new PollServiceRequestManager(this, performPollResponsesAsync, 2, 25000); 2090 {
1959 PollServiceRequestManager.Start(); 2091 PollServiceRequestManager = new PollServiceRequestManager(this, performPollResponsesAsync, 2, 25000);
2092 PollServiceRequestManager.Start();
2093 }
1960 2094
1961 HTTPDRunning = true; 2095 HTTPDRunning = true;
1962 2096
@@ -1970,7 +2104,7 @@ namespace OpenSim.Framework.Servers.HttpServer
1970 catch (Exception e) 2104 catch (Exception e)
1971 { 2105 {
1972 m_log.Error("[BASE HTTP SERVER]: Error - " + e.Message); 2106 m_log.Error("[BASE HTTP SERVER]: Error - " + e.Message);
1973 m_log.Error("[BASE HTTP SERVER]: Tip: Do you have permission to listen on port " + m_port + ", " + m_sslport + "?"); 2107 m_log.Error("[BASE HTTP SERVER]: Tip: Do you have permission to listen on port " + m_port + "?");
1974 2108
1975 // We want this exception to halt the entire server since in current configurations we aren't too 2109 // We want this exception to halt the entire server since in current configurations we aren't too
1976 // useful without inbound HTTP. 2110 // useful without inbound HTTP.
@@ -2135,10 +2269,9 @@ namespace OpenSim.Framework.Servers.HttpServer
2135 string file = Path.Combine(".", "http_500.html"); 2269 string file = Path.Combine(".", "http_500.html");
2136 if (!File.Exists(file)) 2270 if (!File.Exists(file))
2137 return getDefaultHTTP500(); 2271 return getDefaultHTTP500();
2138 2272 string result = string.Empty;
2139 StreamReader sr = File.OpenText(file); 2273 using(StreamReader sr = File.OpenText(file))
2140 string result = sr.ReadToEnd(); 2274 result = sr.ReadToEnd();
2141 sr.Close();
2142 return result; 2275 return result;
2143 } 2276 }
2144 2277