aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Framework/Servers
diff options
context:
space:
mode:
authorTeravus Ovares2008-01-09 04:13:04 +0000
committerTeravus Ovares2008-01-09 04:13:04 +0000
commite1aa83e965440b3e830d599e18ff078104e8a886 (patch)
treeb6f97c44228c41736a7145e8943d4b7c8d535983 /OpenSim/Framework/Servers
parentdump_assets_to_file=true will now cause the asset to go into a UserAssets sub... (diff)
downloadopensim-SC_OLD-e1aa83e965440b3e830d599e18ff078104e8a886.zip
opensim-SC_OLD-e1aa83e965440b3e830d599e18ff078104e8a886.tar.gz
opensim-SC_OLD-e1aa83e965440b3e830d599e18ff078104e8a886.tar.bz2
opensim-SC_OLD-e1aa83e965440b3e830d599e18ff078104e8a886.tar.xz
* Added a hashtable based HTTP processor in preparation of the web_login_key
* Added the web_login_key to the users table * Added happy configurable http error message pages * This update is large enough to have 'awe' value.. so backup your users or weep. * Not tested on MSSQL, even though I added code to update the tables!
Diffstat (limited to 'OpenSim/Framework/Servers')
-rw-r--r--OpenSim/Framework/Servers/BaseHttpServer.cs338
-rw-r--r--OpenSim/Framework/Servers/GenericHTTPMethod.cs34
-rw-r--r--OpenSim/Framework/Servers/IStreamHandler.cs7
3 files changed, 255 insertions, 124 deletions
diff --git a/OpenSim/Framework/Servers/BaseHttpServer.cs b/OpenSim/Framework/Servers/BaseHttpServer.cs
index 004b330..32d65af 100644
--- a/OpenSim/Framework/Servers/BaseHttpServer.cs
+++ b/OpenSim/Framework/Servers/BaseHttpServer.cs
@@ -46,6 +46,8 @@ namespace OpenSim.Framework.Servers
46 protected Dictionary<string, XmlRpcMethod> m_rpcHandlers = new Dictionary<string, XmlRpcMethod>(); 46 protected Dictionary<string, XmlRpcMethod> m_rpcHandlers = new Dictionary<string, XmlRpcMethod>();
47 protected LLSDMethod m_llsdHandler = null; 47 protected LLSDMethod m_llsdHandler = null;
48 protected Dictionary<string, IRequestHandler> m_streamHandlers = new Dictionary<string, IRequestHandler>(); 48 protected Dictionary<string, IRequestHandler> m_streamHandlers = new Dictionary<string, IRequestHandler>();
49 protected Dictionary<string, GenericHTTPMethod> m_HTTPHandlers = new Dictionary<string, GenericHTTPMethod>();
50
49 protected uint m_port; 51 protected uint m_port;
50 protected bool m_ssl = false; 52 protected bool m_ssl = false;
51 protected bool m_firstcaps = true; 53 protected bool m_firstcaps = true;
@@ -92,6 +94,18 @@ namespace OpenSim.Framework.Servers
92 return false; 94 return false;
93 } 95 }
94 96
97 public bool AddHTTPHandler(string method, GenericHTTPMethod handler)
98 {
99 if (!m_HTTPHandlers.ContainsKey(method))
100 {
101 m_HTTPHandlers.Add(method, handler);
102 return true;
103 }
104
105 //must already have a handler for that path so return false
106 return false;
107 }
108
95 public bool SetLLSDHandler(LLSDMethod handler) 109 public bool SetLLSDHandler(LLSDMethod handler)
96 { 110 {
97 m_llsdHandler = handler; 111 m_llsdHandler = handler;
@@ -145,6 +159,10 @@ namespace OpenSim.Framework.Servers
145 { 159 {
146 switch (request.ContentType) 160 switch (request.ContentType)
147 { 161 {
162 case null:
163 case "text/html":
164 HandleHTTPRequest(request, response);
165 break;
148 case "application/xml+llsd": 166 case "application/xml+llsd":
149 HandleLLSDRequests(request, response); 167 HandleLLSDRequests(request, response);
150 break; 168 break;
@@ -184,6 +202,32 @@ namespace OpenSim.Framework.Servers
184 } 202 }
185 } 203 }
186 204
205 private bool TryGetHTTPHandler(string handlerKey, out GenericHTTPMethod HTTPHandler)
206 {
207 string bestMatch = null;
208
209 foreach (string pattern in m_HTTPHandlers.Keys)
210 {
211 if (handlerKey.StartsWith(pattern))
212 {
213 if (String.IsNullOrEmpty(bestMatch) || pattern.Length > bestMatch.Length)
214 {
215 bestMatch = pattern;
216 }
217 }
218 }
219
220 if (String.IsNullOrEmpty(bestMatch))
221 {
222 HTTPHandler = null;
223 return false;
224 }
225 else
226 {
227 HTTPHandler = m_HTTPHandlers[bestMatch];
228 return true;
229 }
230 }
187 private void HandleXmlRpcRequests(HttpListenerRequest request, HttpListenerResponse response) 231 private void HandleXmlRpcRequests(HttpListenerRequest request, HttpListenerResponse response)
188 { 232 {
189 Stream requestStream = request.InputStream; 233 Stream requestStream = request.InputStream;
@@ -204,27 +248,7 @@ namespace OpenSim.Framework.Servers
204 } 248 }
205 catch (XmlException e) 249 catch (XmlException e)
206 { 250 {
207 Hashtable keysvals = new Hashtable(); 251
208 responseString = String.Format("XmlException:\n{0}", e.Message);
209 MainLog.Instance.Error("XML", responseString);
210 string[] querystringkeys = request.QueryString.AllKeys;
211 string[] rHeaders = request.Headers.AllKeys;
212
213
214 foreach (string queryname in querystringkeys)
215 {
216 keysvals.Add(queryname, request.QueryString[queryname]);
217 MainLog.Instance.Warn("HTTP", queryname + "=" + request.QueryString[queryname]);
218 }
219 foreach (string headername in rHeaders)
220 {
221 MainLog.Instance.Warn("HEADER", headername + "=" + request.Headers[headername]);
222 }
223 if (keysvals.ContainsKey("show_login_form"))
224 {
225 HandleHTTPRequest(keysvals, request, response);
226 return;
227 }
228 } 252 }
229 253
230 if (xmlRprcRequest != null) 254 if (xmlRprcRequest != null)
@@ -332,7 +356,7 @@ namespace OpenSim.Framework.Servers
332 } 356 }
333 } 357 }
334 358
335 public void HandleHTTPRequest(Hashtable keysvals, HttpListenerRequest request, HttpListenerResponse response) 359 public void HandleHTTPRequest(HttpListenerRequest request, HttpListenerResponse response)
336 { 360 {
337 // This is a test. There's a workable alternative.. as this way sucks. 361 // This is a test. There's a workable alternative.. as this way sucks.
338 // We'd like to put this into a text file parhaps that's easily editable. 362 // We'd like to put this into a text file parhaps that's easily editable.
@@ -345,119 +369,146 @@ namespace OpenSim.Framework.Servers
345 // I depend on show_login_form being in the secondlife.exe parameters to figure out 369 // I depend on show_login_form being in the secondlife.exe parameters to figure out
346 // to display the form, or process it. 370 // to display the form, or process it.
347 // a better way would be nifty. 371 // a better way would be nifty.
372 Stream requestStream = request.InputStream;
348 373
349 if ((string) keysvals["show_login_form"] == "TRUE") 374 Encoding encoding = Encoding.UTF8;
350 { 375 StreamReader reader = new StreamReader(requestStream, encoding);
351 string responseString = 376
352 "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">"; 377 string requestBody = reader.ReadToEnd();
353 responseString = responseString + "<html xmlns=\"http://www.w3.org/1999/xhtml\">"; 378 reader.Close();
354 responseString = responseString + "<head>"; 379 requestStream.Close();
355 responseString = responseString + 380
356 "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />"; 381 string responseString = String.Empty;
357 responseString = responseString + "<meta http-equiv=\"cache-control\" content=\"no-cache\">"; 382
358 responseString = responseString + "<meta http-equiv=\"Pragma\" content=\"no-cache\">"; 383 Hashtable keysvals = new Hashtable();
359 responseString = responseString + "<title>Second Life Login</title>"; 384
360 responseString = responseString + "<body>"; 385 string[] querystringkeys = request.QueryString.AllKeys;
361 responseString = responseString + "<div id=\"login_box\">"; 386 string[] rHeaders = request.Headers.AllKeys;
362 // Linden Grid Form Post 387
363 //responseString = responseString + "<form action=\"https://secure-web16.secondlife.com/app/login/go.php?show_login_form=True&show_grid=&show_start_location=\" method=\"POST\" id=\"login-form\">"; 388
364 responseString = responseString + "<form action=\"/\" method=\"GET\" id=\"login-form\">"; 389 foreach (string queryname in querystringkeys)
365 390 {
366 responseString = responseString + "<div id=\"message\">"; 391 keysvals.Add(queryname, request.QueryString[queryname]);
367 responseString = responseString + "</div>"; 392 MainLog.Instance.Warn("HTTP", queryname + "=" + request.QueryString[queryname]);
368 responseString = responseString + "<fieldset id=\"firstname\">"; 393 }
369 responseString = responseString + "<legend>First Name:</legend>"; 394 //foreach (string headername in rHeaders)
370 responseString = responseString + 395 //{
371 "<input type=\"text\" id=\"firstname_input\" size=\"15\" maxlength=\"100\" name=\"username\" value=\"" + 396 //MainLog.Instance.Warn("HEADER", headername + "=" + request.Headers[headername]);
372 keysvals["username"] + "\" />"; 397 //}
373 responseString = responseString + "</fieldset>"; 398 if (keysvals.Contains("method"))
374 responseString = responseString + "<fieldset id=\"lastname\">"; 399 {
375 responseString = responseString + "<legend>Last Name:</legend>"; 400 MainLog.Instance.Warn("HTTP", "Contains Method");
376 responseString = responseString + 401 string method = (string) keysvals["method"];
377 "<input type=\"text\" size=\"15\" maxlength=\"100\" name=\"lastname\" value=\"" + 402 MainLog.Instance.Warn("HTTP", requestBody);
378 keysvals["lastname"] + "\" />"; 403 GenericHTTPMethod requestprocessor;
379 responseString = responseString + "</fieldset>"; 404 bool foundHandler = TryGetHTTPHandler(method, out requestprocessor);
380 responseString = responseString + "<fieldset id=\"password\">"; 405 if (foundHandler)
381 responseString = responseString + "<legend>Password:</legend>";
382 responseString = responseString + "<table cellspacing=\"0\" cellpadding=\"0\" border=\"0\">";
383 responseString = responseString + "<tr>";
384 responseString = responseString +
385 "<td colspan=\"2\"><input type=\"password\" size=\"15\" maxlength=\"100\" name=\"password\" value=\"" +
386 keysvals["password"] + "\" /></td>";
387 responseString = responseString + "</tr>";
388 responseString = responseString + "<tr>";
389 responseString = responseString +
390 "<td valign=\"middle\"><input type=\"checkbox\" name=\"remember_password\" id=\"remember_password\" value=\"" +
391 keysvals["remember_password"] + "\" checked style=\"margin-left:0px;\"/></td>";
392 responseString = responseString + "<td><label for=\"remember_password\">Remember password</label></td>";
393 responseString = responseString + "</tr>";
394 responseString = responseString + "</table>";
395 responseString = responseString + "</fieldset>";
396 responseString = responseString + "<input type=\"hidden\" name=\"show_login_form\" value=\"FALSE\" />";
397 responseString = responseString + "<input type=\"hidden\" id=\"grid\" name=\"grid\" value=\"" +
398 keysvals["grid"] + "\" />";
399 responseString = responseString + "<div id=\"submitbtn\">";
400 responseString = responseString + "<input class=\"input_over\" type=\"submit\" value=\"Connect\" />";
401 responseString = responseString + "</div>";
402 responseString = responseString +
403 "<div id=\"connecting\" style=\"visibility:hidden\"><img src=\"/_img/sl_logo_rotate_black.gif\" align=\"absmiddle\"> Connecting...</div>";
404
405 responseString = responseString + "<div id=\"helplinks\">";
406 responseString = responseString +
407 "<a href=\"http://www.secondlife.com/join/index.php\" target=\"_blank\">Create new account</a> | ";
408 responseString = responseString +
409 "<a href=\"http://www.secondlife.com/account/request.php\" target=\"_blank\">Forgot password?</a>";
410 responseString = responseString + "</div>";
411
412 responseString = responseString + "<div id=\"channelinfo\"> " + keysvals["channel"] + " | " +
413 keysvals["version"] + "=" + keysvals["lang"] + "</div>";
414 responseString = responseString + "</form>";
415 responseString = responseString + "<script language=\"JavaScript\">";
416 responseString = responseString + "document.getElementById('firstname_input').focus();";
417 responseString = responseString + "</script>";
418 responseString = responseString + "</div>";
419 responseString = responseString + "</div>";
420 responseString = responseString + "</body>";
421 responseString = responseString + "</html>";
422 response.AddHeader("Content-type", "text/html");
423
424 byte[] buffer = Encoding.UTF8.GetBytes(responseString);
425
426 response.SendChunked = false;
427 response.ContentLength64 = buffer.Length;
428 response.ContentEncoding = Encoding.UTF8;
429 try
430 {
431 response.OutputStream.Write(buffer, 0, buffer.Length);
432 }
433 catch (Exception ex)
434 { 406 {
435 MainLog.Instance.Warn("HTTPD", "Error - " + ex.Message); 407 Hashtable responsedata = requestprocessor(keysvals);
408 DoHTTPGruntWork(responsedata,response);
409
410 //SendHTML500(response);
411
436 } 412 }
437 finally 413 else
438 { 414 {
439 response.OutputStream.Close(); 415 MainLog.Instance.Warn("HTTP", "Handler Not Found");
416 SendHTML404(response);
440 } 417 }
441 } // show_login_form == "TRUE" 418 }
442 else 419 else
443 { 420 {
444 // show_login_form is present but FALSE 421 MainLog.Instance.Warn("HTTP", "No Method specified");
445 // 422 SendHTML404(response);
446 // The idea here is that we're telling the client to log in immediately here using the following information 423 }
447 // For my testing, I'm hard coding the web_login_key temporarily. 424 }
448 // Telling the client to go to the new improved SLURL for immediate logins 425
426 private void DoHTTPGruntWork(Hashtable responsedata, HttpListenerResponse response)
427 {
428 int responsecode = (int)responsedata["int_response_code"];
429 string responseString = (string)responsedata["str_response_string"];
430
431 // We're forgoing the usual error status codes here because the client
432 // ignores anything but 200 and 301
449 433
450 // The fact that it says grid=Other is important 434 response.StatusCode = 200;
451 435
452 // 436 if (responsecode == 301)
437 {
438 response.RedirectLocation = (string)responsedata["str_redirect_location"];
439 response.StatusCode = responsecode;
440 }
441 response.AddHeader("Content-type", "text/html");
453 442
454 response.StatusCode = 301; 443 byte[] buffer = Encoding.UTF8.GetBytes(responseString);
455 response.RedirectLocation = "secondlife:///app/login?first_name=" + keysvals["username"] + "&last_name=" +
456 keysvals["lastname"] +
457 "&location=home&grid=other&web_login_key=796f2b2a-0131-41e4-af12-00f60c24c458";
458 444
445 response.SendChunked = false;
446 response.ContentLength64 = buffer.Length;
447 response.ContentEncoding = Encoding.UTF8;
448 try
449 {
450 response.OutputStream.Write(buffer, 0, buffer.Length);
451 }
452 catch (Exception ex)
453 {
454 MainLog.Instance.Warn("HTTPD", "Error - " + ex.Message);
455 }
456 finally
457 {
459 response.OutputStream.Close(); 458 response.OutputStream.Close();
460 } // show_login_form == "FALSE" 459 }
460
461
462 }
463 public void SendHTML404(HttpListenerResponse response)
464 {
465 // I know this statuscode is dumb, but the client doesn't respond to 404s and 500s
466 response.StatusCode = 200;
467 response.AddHeader("Content-type", "text/html");
468
469 string responseString = GetHTTP404();
470 byte[] buffer = Encoding.UTF8.GetBytes(responseString);
471
472 response.SendChunked = false;
473 response.ContentLength64 = buffer.Length;
474 response.ContentEncoding = Encoding.UTF8;
475 try
476 {
477 response.OutputStream.Write(buffer, 0, buffer.Length);
478 }
479 catch (Exception ex)
480 {
481 MainLog.Instance.Warn("HTTPD", "Error - " + ex.Message);
482 }
483 finally
484 {
485 response.OutputStream.Close();
486 }
487 }
488 public void SendHTML500(HttpListenerResponse response)
489 {
490 // I know this statuscode is dumb, but the client doesn't respond to 404s and 500s
491 response.StatusCode = 200;
492 response.AddHeader("Content-type", "text/html");
493
494 string responseString = GetHTTP500();
495 byte[] buffer = Encoding.UTF8.GetBytes(responseString);
496
497 response.SendChunked = false;
498 response.ContentLength64 = buffer.Length;
499 response.ContentEncoding = Encoding.UTF8;
500 try
501 {
502 response.OutputStream.Write(buffer, 0, buffer.Length);
503 }
504 catch (Exception ex)
505 {
506 MainLog.Instance.Warn("HTTPD", "Error - " + ex.Message);
507 }
508 finally
509 {
510 response.OutputStream.Close();
511 }
461 } 512 }
462 513
463 public void Start() 514 public void Start()
@@ -504,5 +555,46 @@ namespace OpenSim.Framework.Servers
504 { 555 {
505 m_streamHandlers.Remove(GetHandlerKey(httpMethod, path)); 556 m_streamHandlers.Remove(GetHandlerKey(httpMethod, path));
506 } 557 }
558
559 public void RemoveHTTPHandler(string httpMethod, string path)
560 {
561 m_HTTPHandlers.Remove(GetHandlerKey(httpMethod, path));
562 }
563
564 public string GetHTTP404()
565 {
566 string file = Path.Combine(Util.configDir(), "http_404.html");
567 if (!File.Exists(file))
568 return getDefaultHTTP404();
569
570 StreamReader sr = File.OpenText(file);
571 string result = sr.ReadToEnd();
572 sr.Close();
573 return result;
574 }
575
576 public string GetHTTP500()
577 {
578 string file = Path.Combine(Util.configDir(), "http_500.html");
579 if (!File.Exists(file))
580 return getDefaultHTTP500();
581
582 StreamReader sr = File.OpenText(file);
583 string result = sr.ReadToEnd();
584 sr.Close();
585 return result;
586 }
587
588 // Fallback HTTP responses in case the HTTP error response files don't exist
589 private string getDefaultHTTP404()
590 {
591 return "<HTML><HEAD><TITLE>404 Page not found</TITLE><BODY><BR /><H1>Ooops!</H1><P>The page you requested has been obsconded with by knomes. Find hippos quick!</P></BODY></HTML>";
592 }
593
594 private string getDefaultHTTP500()
595 {
596 return "<HTML><HEAD><TITLE>500 Internal Server Error</TITLE><BODY><BR /><H1>Ooops!</H1><P>The server you requested is overun by knomes! Find hippos quick!</P></BODY></HTML>";
597 }
598
507 } 599 }
508} 600}
diff --git a/OpenSim/Framework/Servers/GenericHTTPMethod.cs b/OpenSim/Framework/Servers/GenericHTTPMethod.cs
new file mode 100644
index 0000000..76aa8fe
--- /dev/null
+++ b/OpenSim/Framework/Servers/GenericHTTPMethod.cs
@@ -0,0 +1,34 @@
1/*
2* Copyright (c) Contributors, http://opensimulator.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;
30
31namespace OpenSim.Framework.Servers
32{
33 public delegate Hashtable GenericHTTPMethod(Hashtable request);
34} \ No newline at end of file
diff --git a/OpenSim/Framework/Servers/IStreamHandler.cs b/OpenSim/Framework/Servers/IStreamHandler.cs
index c87937a..d52f9ac 100644
--- a/OpenSim/Framework/Servers/IStreamHandler.cs
+++ b/OpenSim/Framework/Servers/IStreamHandler.cs
@@ -25,7 +25,7 @@
25* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26* 26*
27*/ 27*/
28 28using System.Collections;
29using System.IO; 29using System.IO;
30 30
31namespace OpenSim.Framework.Servers 31namespace OpenSim.Framework.Servers
@@ -40,6 +40,7 @@ namespace OpenSim.Framework.Servers
40 40
41 // Return path 41 // Return path
42 string Path { get; } 42 string Path { get; }
43
43 } 44 }
44 45
45 public interface IStreamedRequestHandler : IRequestHandler 46 public interface IStreamedRequestHandler : IRequestHandler
@@ -53,4 +54,8 @@ namespace OpenSim.Framework.Servers
53 // Handle request stream, return byte array 54 // Handle request stream, return byte array
54 void Handle(string path, Stream request, Stream response); 55 void Handle(string path, Stream request, Stream response);
55 } 56 }
57 public interface IGenericHTTPHandler : IRequestHandler
58 {
59 Hashtable Handle(string path, Hashtable request);
60 }
56} \ No newline at end of file 61} \ No newline at end of file