OpenSim
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros
BaseHttpServer.cs
Go to the documentation of this file.
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 OpenSimulator 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 
28 using System;
29 using System.Collections;
30 using System.Collections.Generic;
31 using System.Collections.Specialized;
32 using System.IO;
33 using System.Net;
34 using System.Net.Sockets;
35 using System.Security.Cryptography.X509Certificates;
36 using System.Reflection;
37 using System.Globalization;
38 using System.Text;
39 using System.Threading;
40 using System.Xml;
41 using HttpServer;
42 using log4net;
43 using Nwc.XmlRpc;
44 using OpenMetaverse.StructuredData;
48 using OpenSim.Framework.Monitoring;
49 using System.IO.Compression;
50 
51 namespace OpenSim.Framework.Servers.HttpServer
52 {
53  public class BaseHttpServer : IHttpServer
54  {
55  private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
56  private HttpServerLogWriter httpserverlog = new HttpServerLogWriter();
57  private static Encoding UTF8NoBOM = new System.Text.UTF8Encoding(false);
58 
66  public delegate void WebSocketRequestDelegate(string servicepath, WebSocketHttpServerHandler handler);
67 
74  public int DebugLevel { get; set; }
75 
83  public int RequestNumber { get; private set; }
84 
88  private Stat m_requestsProcessedStat;
89 
90  private volatile int NotSocketErrors = 0;
91  public volatile bool HTTPDRunning = false;
92 
93  // protected HttpListener m_httpListener;
95  protected Dictionary<string, XmlRpcMethod> m_rpcHandlers = new Dictionary<string, XmlRpcMethod>();
96  protected Dictionary<string, JsonRPCMethod> jsonRpcHandlers = new Dictionary<string, JsonRPCMethod>();
97  protected Dictionary<string, bool> m_rpcHandlersKeepAlive = new Dictionary<string, bool>();
98  protected DefaultLLSDMethod m_defaultLlsdHandler = null; // <-- Moving away from the monolithic.. and going to /registered/
99  protected Dictionary<string, LLSDMethod> m_llsdHandlers = new Dictionary<string, LLSDMethod>();
100  protected Dictionary<string, IRequestHandler> m_streamHandlers = new Dictionary<string, IRequestHandler>();
101  protected Dictionary<string, GenericHTTPMethod> m_HTTPHandlers = new Dictionary<string, GenericHTTPMethod>();
102 // protected Dictionary<string, IHttpAgentHandler> m_agentHandlers = new Dictionary<string, IHttpAgentHandler>();
103  protected Dictionary<string, PollServiceEventArgs> m_pollHandlers =
104  new Dictionary<string, PollServiceEventArgs>();
105 
106  protected Dictionary<string, WebSocketRequestDelegate> m_WebSocketHandlers =
107  new Dictionary<string, WebSocketRequestDelegate>();
108 
109  protected uint m_port;
110  protected uint m_sslport;
111  protected bool m_ssl;
112  private X509Certificate2 m_cert;
113  protected bool m_firstcaps = true;
114  protected string m_SSLCommonName = "";
115 
116  protected IPAddress m_listenIPAddress = IPAddress.Any;
117 
119 
120  public uint SSLPort
121  {
122  get { return m_sslport; }
123  }
124 
125  public string SSLCommonName
126  {
127  get { return m_SSLCommonName; }
128  }
129 
130  public uint Port
131  {
132  get { return m_port; }
133  }
134 
135  public bool UseSSL
136  {
137  get { return m_ssl; }
138  }
139 
140  public IPAddress ListenIPAddress
141  {
142  get { return m_listenIPAddress; }
143  set { m_listenIPAddress = value; }
144  }
145 
146  public BaseHttpServer(uint port)
147  {
148  m_port = port;
149  }
150 
151  public BaseHttpServer(uint port, bool ssl) : this (port)
152  {
153  m_ssl = ssl;
154  }
155 
156  public BaseHttpServer(uint port, bool ssl, uint sslport, string CN) : this (port, ssl)
157  {
158  if (m_ssl)
159  {
160  m_sslport = sslport;
161  }
162  }
163 
164  public BaseHttpServer(uint port, bool ssl, string CPath, string CPass) : this (port, ssl)
165  {
166  if (m_ssl)
167  {
168  m_cert = new X509Certificate2(CPath, CPass);
169  }
170  }
171 
176  public void AddStreamHandler(IRequestHandler handler)
177  {
178  string httpMethod = handler.HttpMethod;
179  string path = handler.Path;
180  string handlerKey = GetHandlerKey(httpMethod, path);
181 
182  lock (m_streamHandlers)
183  {
184  if (!m_streamHandlers.ContainsKey(handlerKey))
185  {
186  // m_log.DebugFormat("[BASE HTTP SERVER]: Adding handler key {0}", handlerKey);
187  m_streamHandlers.Add(handlerKey, handler);
188  }
189  }
190  }
191 
192  public void AddWebSocketHandler(string servicepath, WebSocketRequestDelegate handler)
193  {
194  lock (m_WebSocketHandlers)
195  {
196  if (!m_WebSocketHandlers.ContainsKey(servicepath))
197  m_WebSocketHandlers.Add(servicepath, handler);
198  }
199  }
200 
201  public void RemoveWebSocketHandler(string servicepath)
202  {
203  lock (m_WebSocketHandlers)
204  if (m_WebSocketHandlers.ContainsKey(servicepath))
205  m_WebSocketHandlers.Remove(servicepath);
206  }
207 
208  public List<string> GetStreamHandlerKeys()
209  {
210  lock (m_streamHandlers)
211  return new List<string>(m_streamHandlers.Keys);
212  }
213 
214  private static string GetHandlerKey(string httpMethod, string path)
215  {
216  return httpMethod + ":" + path;
217  }
218 
219  public bool AddXmlRPCHandler(string method, XmlRpcMethod handler)
220  {
221  return AddXmlRPCHandler(method, handler, true);
222  }
223 
224  public bool AddXmlRPCHandler(string method, XmlRpcMethod handler, bool keepAlive)
225  {
226  lock (m_rpcHandlers)
227  {
228  m_rpcHandlers[method] = handler;
229  m_rpcHandlersKeepAlive[method] = keepAlive; // default
230  }
231 
232  return true;
233  }
234 
235  public XmlRpcMethod GetXmlRPCHandler(string method)
236  {
237  lock (m_rpcHandlers)
238  {
239  if (m_rpcHandlers.ContainsKey(method))
240  {
241  return m_rpcHandlers[method];
242  }
243  else
244  {
245  return null;
246  }
247  }
248  }
249 
250  public List<string> GetXmlRpcHandlerKeys()
251  {
252  lock (m_rpcHandlers)
253  return new List<string>(m_rpcHandlers.Keys);
254  }
255 
256  // JsonRPC
257  public bool AddJsonRPCHandler(string method, JsonRPCMethod handler)
258  {
259  lock(jsonRpcHandlers)
260  {
261  jsonRpcHandlers.Add(method, handler);
262  }
263  return true;
264  }
265 
266  public JsonRPCMethod GetJsonRPCHandler(string method)
267  {
268  lock (jsonRpcHandlers)
269  {
270  if (jsonRpcHandlers.ContainsKey(method))
271  {
272  return jsonRpcHandlers[method];
273  }
274  else
275  {
276  return null;
277  }
278  }
279  }
280 
281  public List<string> GetJsonRpcHandlerKeys()
282  {
283  lock (jsonRpcHandlers)
284  return new List<string>(jsonRpcHandlers.Keys);
285  }
286 
287  public bool AddHTTPHandler(string methodName, GenericHTTPMethod handler)
288  {
289  //m_log.DebugFormat("[BASE HTTP SERVER]: Registering {0}", methodName);
290 
291  lock (m_HTTPHandlers)
292  {
293  if (!m_HTTPHandlers.ContainsKey(methodName))
294  {
295  m_HTTPHandlers.Add(methodName, handler);
296  return true;
297  }
298  }
299 
300  //must already have a handler for that path so return false
301  return false;
302  }
303 
304  public List<string> GetHTTPHandlerKeys()
305  {
306  lock (m_HTTPHandlers)
307  return new List<string>(m_HTTPHandlers.Keys);
308  }
309 
310  public bool AddPollServiceHTTPHandler(string methodName, PollServiceEventArgs args)
311  {
312  lock (m_pollHandlers)
313  {
314  if (!m_pollHandlers.ContainsKey(methodName))
315  {
316  m_pollHandlers.Add(methodName, args);
317  return true;
318  }
319  }
320 
321  return false;
322  }
323 
324  public List<string> GetPollServiceHandlerKeys()
325  {
326  lock (m_pollHandlers)
327  return new List<string>(m_pollHandlers.Keys);
328  }
329 
330 // // Note that the agent string is provided simply to differentiate
331 // // the handlers - it is NOT required to be an actual agent header
332 // // value.
333 // public bool AddAgentHandler(string agent, IHttpAgentHandler handler)
334 // {
335 // lock (m_agentHandlers)
336 // {
337 // if (!m_agentHandlers.ContainsKey(agent))
338 // {
339 // m_agentHandlers.Add(agent, handler);
340 // return true;
341 // }
342 // }
343 //
344 // //must already have a handler for that path so return false
345 // return false;
346 // }
347 //
348 // public List<string> GetAgentHandlerKeys()
349 // {
350 // lock (m_agentHandlers)
351 // return new List<string>(m_agentHandlers.Keys);
352 // }
353 
354  public bool AddLLSDHandler(string path, LLSDMethod handler)
355  {
356  lock (m_llsdHandlers)
357  {
358  if (!m_llsdHandlers.ContainsKey(path))
359  {
360  m_llsdHandlers.Add(path, handler);
361  return true;
362  }
363  }
364  return false;
365  }
366 
367  public List<string> GetLLSDHandlerKeys()
368  {
369  lock (m_llsdHandlers)
370  return new List<string>(m_llsdHandlers.Keys);
371  }
372 
374  {
375  m_defaultLlsdHandler = handler;
376  return true;
377  }
378 
379  public void OnRequest(object source, RequestEventArgs args)
380  {
381  RequestNumber++;
382 
383  try
384  {
385  IHttpClientContext context = (IHttpClientContext)source;
386  IHttpRequest request = args.Request;
387 
388  PollServiceEventArgs psEvArgs;
389 
390  if (TryGetPollServiceHTTPHandler(request.UriPath.ToString(), out psEvArgs))
391  {
392  psEvArgs.RequestsReceived++;
393 
394  PollServiceHttpRequest psreq = new PollServiceHttpRequest(psEvArgs, context, request);
395 
396  if (psEvArgs.Request != null)
397  {
398  OSHttpRequest req = new OSHttpRequest(context, request);
399 
400  Stream requestStream = req.InputStream;
401 
402  Encoding encoding = Encoding.UTF8;
403  StreamReader reader = new StreamReader(requestStream, encoding);
404 
405  string requestBody = reader.ReadToEnd();
406  reader.Close();
407 
408  Hashtable keysvals = new Hashtable();
409  Hashtable headervals = new Hashtable();
410 
411  string[] querystringkeys = req.QueryString.AllKeys;
412  string[] rHeaders = req.Headers.AllKeys;
413 
414  keysvals.Add("body", requestBody);
415  keysvals.Add("uri", req.RawUrl);
416  keysvals.Add("content-type", req.ContentType);
417  keysvals.Add("http-method", req.HttpMethod);
418 
419  foreach (string queryname in querystringkeys)
420  {
421  keysvals.Add(queryname, req.QueryString[queryname]);
422  }
423 
424  foreach (string headername in rHeaders)
425  {
426  headervals[headername] = req.Headers[headername];
427  }
428 
429  keysvals.Add("headers", headervals);
430  keysvals.Add("querystringkeys", querystringkeys);
431 
432  psEvArgs.Request(psreq.RequestID, keysvals);
433  }
434 
435  PollServiceRequestManager.Enqueue(psreq);
436  }
437  else
438  {
439  OnHandleRequestIOThread(context, request);
440  }
441  }
442  catch (Exception e)
443  {
444  m_log.Error(String.Format("[BASE HTTP SERVER]: OnRequest() failed: {0} ", e.Message), e);
445  }
446  }
447 
448  private void OnHandleRequestIOThread(IHttpClientContext context, IHttpRequest request)
449  {
450  OSHttpRequest req = new OSHttpRequest(context, request);
451  WebSocketRequestDelegate dWebSocketRequestDelegate = null;
452  lock (m_WebSocketHandlers)
453  {
454  if (m_WebSocketHandlers.ContainsKey(req.RawUrl))
455  dWebSocketRequestDelegate = m_WebSocketHandlers[req.RawUrl];
456  }
457  if (dWebSocketRequestDelegate != null)
458  {
459  dWebSocketRequestDelegate(req.Url.AbsolutePath, new WebSocketHttpServerHandler(req, context, 8192));
460  return;
461  }
462 
463  OSHttpResponse resp = new OSHttpResponse(new HttpResponse(context, request),context);
464  resp.ReuseContext = false;
465  HandleRequest(req, resp);
466 
467  // !!!HACK ALERT!!!
468  // There seems to be a bug in the underlying http code that makes subsequent requests
469  // come up with trash in Accept headers. Until that gets fixed, we're cleaning them up here.
470  if (request.AcceptTypes != null)
471  for (int i = 0; i < request.AcceptTypes.Length; i++)
472  request.AcceptTypes[i] = string.Empty;
473  }
474 
475  // public void ConvertIHttpClientContextToOSHttp(object stateinfo)
476  // {
477  // HttpServerContextObj objstate = (HttpServerContextObj)stateinfo;
478 
479  // OSHttpRequest request = objstate.oreq;
480  // OSHttpResponse resp = objstate.oresp;
481 
482  // HandleRequest(request,resp);
483  // }
484 
490  public virtual void HandleRequest(OSHttpRequest request, OSHttpResponse response)
491  {
492  if (request.HttpMethod == String.Empty) // Can't handle empty requests, not wasting a thread
493  {
494  try
495  {
496  byte[] buffer500 = SendHTML500(response);
497  response.OutputStream.Write(buffer500, 0, buffer500.Length);
498  response.Send();
499  }
500  catch
501  {
502  }
503 
504  return;
505  }
506 
507  string requestMethod = request.HttpMethod;
508  string uriString = request.RawUrl;
509 
510  int requestStartTick = Environment.TickCount;
511 
512  // Will be adjusted later on.
513  int requestEndTick = requestStartTick;
514 
515  IRequestHandler requestHandler = null;
516 
517  try
518  {
519  // OpenSim.Framework.WebUtil.OSHeaderRequestID
520 // if (request.Headers["opensim-request-id"] != null)
521 // reqnum = String.Format("{0}:{1}",request.RemoteIPEndPoint,request.Headers["opensim-request-id"]);
522  //m_log.DebugFormat("[BASE HTTP SERVER]: <{0}> handle request for {1}",reqnum,request.RawUrl);
523 
524  Culture.SetCurrentCulture();
525 
526 // // This is the REST agent interface. We require an agent to properly identify
527 // // itself. If the REST handler recognizes the prefix it will attempt to
528 // // satisfy the request. If it is not recognizable, and no damage has occurred
529 // // the request can be passed through to the other handlers. This is a low
530 // // probability event; if a request is matched it is normally expected to be
531 // // handled
532 // IHttpAgentHandler agentHandler;
533 //
534 // if (TryGetAgentHandler(request, response, out agentHandler))
535 // {
536 // if (HandleAgentRequest(agentHandler, request, response))
537 // {
538 // requestEndTick = Environment.TickCount;
539 // return;
540 // }
541 // }
542 
543  //response.KeepAlive = true;
544  response.SendChunked = false;
545 
546  string path = request.RawUrl;
547  string handlerKey = GetHandlerKey(request.HttpMethod, path);
548  byte[] buffer = null;
549 
550  if (TryGetStreamHandler(handlerKey, out requestHandler))
551  {
552  if (DebugLevel >= 3)
553  LogIncomingToStreamHandler(request, requestHandler);
554 
555  response.ContentType = requestHandler.ContentType; // Lets do this defaulting before in case handler has varying content type.
556 
557  if (requestHandler is IStreamedRequestHandler)
558  {
559  IStreamedRequestHandler streamedRequestHandler = requestHandler as IStreamedRequestHandler;
560 
561  buffer = streamedRequestHandler.Handle(path, request.InputStream, request, response);
562  }
563  else if (requestHandler is IGenericHTTPHandler)
564  {
565  //m_log.Debug("[BASE HTTP SERVER]: Found Caps based HTTP Handler");
566  IGenericHTTPHandler HTTPRequestHandler = requestHandler as IGenericHTTPHandler;
567  Stream requestStream = request.InputStream;
568 
569  Encoding encoding = Encoding.UTF8;
570  StreamReader reader = new StreamReader(requestStream, encoding);
571 
572  string requestBody = reader.ReadToEnd();
573 
574  reader.Close();
575  //requestStream.Close();
576 
577  Hashtable keysvals = new Hashtable();
578  Hashtable headervals = new Hashtable();
579  //string host = String.Empty;
580 
581  string[] querystringkeys = request.QueryString.AllKeys;
582  string[] rHeaders = request.Headers.AllKeys;
583 
584  foreach (string queryname in querystringkeys)
585  {
586  keysvals.Add(queryname, request.QueryString[queryname]);
587  }
588 
589  foreach (string headername in rHeaders)
590  {
591  //m_log.Warn("[HEADER]: " + headername + "=" + request.Headers[headername]);
592  headervals[headername] = request.Headers[headername];
593  }
594 
595  // if (headervals.Contains("Host"))
596  // {
597  // host = (string)headervals["Host"];
598  // }
599 
600  keysvals.Add("requestbody", requestBody);
601  keysvals.Add("headers",headervals);
602  if (keysvals.Contains("method"))
603  {
604  //m_log.Warn("[HTTP]: Contains Method");
605  //string method = (string)keysvals["method"];
606  //m_log.Warn("[HTTP]: " + requestBody);
607 
608  }
609 
610  buffer = DoHTTPGruntWork(HTTPRequestHandler.Handle(path, keysvals), response);
611  }
612  else
613  {
614  IStreamHandler streamHandler = (IStreamHandler)requestHandler;
615 
616  using (MemoryStream memoryStream = new MemoryStream())
617  {
618  streamHandler.Handle(path, request.InputStream, memoryStream, request, response);
619  memoryStream.Flush();
620  buffer = memoryStream.ToArray();
621  }
622  }
623  }
624  else
625  {
626  switch (request.ContentType)
627  {
628  case null:
629  case "text/html":
630  if (DebugLevel >= 3)
631  LogIncomingToContentTypeHandler(request);
632 
633  buffer = HandleHTTPRequest(request, response);
634  break;
635 
636  case "application/llsd+xml":
637  case "application/xml+llsd":
638  case "application/llsd+json":
639  if (DebugLevel >= 3)
640  LogIncomingToContentTypeHandler(request);
641 
642  buffer = HandleLLSDRequests(request, response);
643  break;
644 
645  case "application/json-rpc":
646  if (DebugLevel >= 3)
647  LogIncomingToContentTypeHandler(request);
648 
649  buffer = HandleJsonRpcRequests(request, response);
650  break;
651 
652  case "text/xml":
653  case "application/xml":
654  case "application/json":
655 
656  default:
657  //m_log.Info("[Debug BASE HTTP SERVER]: in default handler");
658  // Point of note.. the DoWeHaveA methods check for an EXACT path
659  // if (request.RawUrl.Contains("/CAPS/EQG"))
660  // {
661  // int i = 1;
662  // }
663  //m_log.Info("[Debug BASE HTTP SERVER]: Checking for LLSD Handler");
664  if (DoWeHaveALLSDHandler(request.RawUrl))
665  {
666  if (DebugLevel >= 3)
667  LogIncomingToContentTypeHandler(request);
668 
669  buffer = HandleLLSDRequests(request, response);
670  }
671  // m_log.DebugFormat("[BASE HTTP SERVER]: Checking for HTTP Handler for request {0}", request.RawUrl);
672  else if (DoWeHaveAHTTPHandler(request.RawUrl))
673  {
674  if (DebugLevel >= 3)
675  LogIncomingToContentTypeHandler(request);
676 
677  buffer = HandleHTTPRequest(request, response);
678  }
679  else
680  {
681  if (DebugLevel >= 3)
682  LogIncomingToXmlRpcHandler(request);
683 
684  // generic login request.
685  buffer = HandleXmlRpcRequests(request, response);
686  }
687 
688  break;
689  }
690  }
691 
692  request.InputStream.Close();
693 
694  if (buffer != null)
695  {
696  if (WebUtil.DebugLevel >= 5)
697  {
698  string output = System.Text.Encoding.UTF8.GetString(buffer);
699 
700  if (WebUtil.DebugLevel >= 6)
701  {
702  // Always truncate binary blobs. We don't have a ContentType, so detect them using the request name.
703  if ((requestHandler != null && requestHandler.Name == "GetMesh"))
704  {
705  if (output.Length > WebUtil.MaxRequestDiagLength)
706  output = output.Substring(0, WebUtil.MaxRequestDiagLength) + "...";
707  }
708  }
709 
710  WebUtil.LogResponseDetail(RequestNumber, output);
711  }
712 
713  if (!response.SendChunked && response.ContentLength64 <= 0)
714  response.ContentLength64 = buffer.LongLength;
715 
716  response.OutputStream.Write(buffer, 0, buffer.Length);
717  }
718 
719  // Do not include the time taken to actually send the response to the caller in the measurement
720  // time. This is to avoid logging when it's the client that is slow to process rather than the
721  // server
722  requestEndTick = Environment.TickCount;
723 
724  response.Send();
725 
726  //response.OutputStream.Close();
727 
728  //response.FreeContext();
729  }
730  catch (SocketException e)
731  {
732  // At least on linux, it appears that if the client makes a request without requiring the response,
733  // an unconnected socket exception is thrown when we close the response output stream. There's no
734  // obvious way to tell if the client didn't require the response, so instead we'll catch and ignore
735  // the exception instead.
736  //
737  // An alternative may be to turn off all response write exceptions on the HttpListener, but let's go
738  // with the minimum first
739  m_log.Warn(String.Format("[BASE HTTP SERVER]: HandleRequest threw {0}.\nNOTE: this may be spurious on Linux ", e.Message), e);
740  }
741  catch (IOException e)
742  {
743  m_log.Error("[BASE HTTP SERVER]: HandleRequest() threw exception ", e);
744  }
745  catch (Exception e)
746  {
747  m_log.Error("[BASE HTTP SERVER]: HandleRequest() threw exception ", e);
748  try
749  {
750  byte[] buffer500 = SendHTML500(response);
751  response.OutputStream.Write(buffer500, 0, buffer500.Length);
752  response.Send();
753  }
754  catch
755  {
756  }
757  }
758  finally
759  {
760  // Every month or so this will wrap and give bad numbers, not really a problem
761  // since its just for reporting
762  int tickdiff = requestEndTick - requestStartTick;
763  if (tickdiff > 3000 && (requestHandler == null || requestHandler.Name == null || requestHandler.Name != "GetTexture"))
764  {
765  m_log.InfoFormat(
766  "[LOGHTTP] Slow handling of {0} {1} {2} {3} {4} from {5} took {6}ms",
767  RequestNumber,
768  requestMethod,
769  uriString,
770  requestHandler != null ? requestHandler.Name : "",
771  requestHandler != null ? requestHandler.Description : "",
772  request.RemoteIPEndPoint,
773  tickdiff);
774  }
775  else if (DebugLevel >= 4)
776  {
777  m_log.DebugFormat(
778  "[LOGHTTP] HTTP IN {0} :{1} took {2}ms",
779  RequestNumber,
780  Port,
781  tickdiff);
782  }
783  }
784  }
785 
786  private void LogIncomingToStreamHandler(OSHttpRequest request, IRequestHandler requestHandler)
787  {
788  m_log.DebugFormat(
789  "[LOGHTTP] HTTP IN {0} :{1} stream handler {2} {3} {4} {5} from {6}",
790  RequestNumber,
791  Port,
792  request.HttpMethod,
793  request.Url.PathAndQuery,
794  requestHandler.Name,
795  requestHandler.Description,
796  request.RemoteIPEndPoint);
797 
798  if (DebugLevel >= 5)
799  LogIncomingInDetail(request);
800  }
801 
802  private void LogIncomingToContentTypeHandler(OSHttpRequest request)
803  {
804  m_log.DebugFormat(
805  "[LOGHTTP] HTTP IN {0} :{1} {2} content type handler {3} {4} from {5}",
806  RequestNumber,
807  Port,
808  string.IsNullOrEmpty(request.ContentType) ? "not set" : request.ContentType,
809  request.HttpMethod,
810  request.Url.PathAndQuery,
811  request.RemoteIPEndPoint);
812 
813  if (DebugLevel >= 5)
814  LogIncomingInDetail(request);
815  }
816 
817  private void LogIncomingToXmlRpcHandler(OSHttpRequest request)
818  {
819  m_log.DebugFormat(
820  "[LOGHTTP] HTTP IN {0} :{1} assumed generic XMLRPC request {2} {3} from {4}",
821  RequestNumber,
822  Port,
823  request.HttpMethod,
824  request.Url.PathAndQuery,
825  request.RemoteIPEndPoint);
826 
827  if (DebugLevel >= 5)
828  LogIncomingInDetail(request);
829  }
830 
831  private void LogIncomingInDetail(OSHttpRequest request)
832  {
833  if (request.ContentType == "application/octet-stream")
834  return; // never log these; they're just binary data
835 
836  Stream inputStream = Util.Copy(request.InputStream);
837  Stream innerStream = null;
838  try
839  {
840  if ((request.Headers["Content-Encoding"] == "gzip") || (request.Headers["X-Content-Encoding"] == "gzip"))
841  {
842  innerStream = inputStream;
843  inputStream = new GZipStream(innerStream, System.IO.Compression.CompressionMode.Decompress);
844  }
845 
846  using (StreamReader reader = new StreamReader(inputStream, Encoding.UTF8))
847  {
848  string output;
849 
850  if (DebugLevel == 5)
851  {
852  char[] chars = new char[WebUtil.MaxRequestDiagLength + 1]; // +1 so we know to add "..." only if needed
853  int len = reader.Read(chars, 0, WebUtil.MaxRequestDiagLength + 1);
854  output = new string(chars, 0, Math.Min(len, WebUtil.MaxRequestDiagLength));
855  if (len > WebUtil.MaxRequestDiagLength)
856  output += "...";
857  }
858  else
859  {
860  output = reader.ReadToEnd();
861  }
862 
863  m_log.DebugFormat("[LOGHTTP] {0}", Util.BinaryToASCII(output));
864  }
865  }
866  finally
867  {
868  if (innerStream != null)
869  innerStream.Dispose();
870  inputStream.Dispose();
871  }
872  }
873 
874  private readonly string HANDLER_SEPARATORS = "/?&#-";
875 
876  private bool TryGetStreamHandler(string handlerKey, out IRequestHandler streamHandler)
877  {
878  string bestMatch = null;
879 
880  lock (m_streamHandlers)
881  {
882  foreach (string pattern in m_streamHandlers.Keys)
883  {
884  if ((handlerKey == pattern)
885  || (handlerKey.StartsWith(pattern) && (HANDLER_SEPARATORS.IndexOf(handlerKey[pattern.Length]) >= 0)))
886  {
887  if (String.IsNullOrEmpty(bestMatch) || pattern.Length > bestMatch.Length)
888  {
889  bestMatch = pattern;
890  }
891  }
892  }
893 
894  if (String.IsNullOrEmpty(bestMatch))
895  {
896  streamHandler = null;
897  return false;
898  }
899  else
900  {
901  streamHandler = m_streamHandlers[bestMatch];
902  return true;
903  }
904  }
905  }
906 
907  private bool TryGetPollServiceHTTPHandler(string handlerKey, out PollServiceEventArgs oServiceEventArgs)
908  {
909  string bestMatch = null;
910 
911  lock (m_pollHandlers)
912  {
913  foreach (string pattern in m_pollHandlers.Keys)
914  {
915  if ((handlerKey == pattern)
916  || (handlerKey.StartsWith(pattern) && (HANDLER_SEPARATORS.IndexOf(handlerKey[pattern.Length]) >= 0)))
917  {
918  if (String.IsNullOrEmpty(bestMatch) || pattern.Length > bestMatch.Length)
919  {
920  bestMatch = pattern;
921  }
922  }
923  }
924 
925  if (String.IsNullOrEmpty(bestMatch))
926  {
927  oServiceEventArgs = null;
928  return false;
929  }
930  else
931  {
932  oServiceEventArgs = m_pollHandlers[bestMatch];
933  return true;
934  }
935  }
936  }
937 
938  private bool TryGetHTTPHandler(string handlerKey, out GenericHTTPMethod HTTPHandler)
939  {
940 // m_log.DebugFormat("[BASE HTTP HANDLER]: Looking for HTTP handler for {0}", handlerKey);
941 
942  string bestMatch = null;
943 
944  lock (m_HTTPHandlers)
945  {
946  foreach (string pattern in m_HTTPHandlers.Keys)
947  {
948  if ((handlerKey == pattern)
949  || (handlerKey.StartsWith(pattern) && (HANDLER_SEPARATORS.IndexOf(handlerKey[pattern.Length]) >= 0)))
950  {
951  if (String.IsNullOrEmpty(bestMatch) || pattern.Length > bestMatch.Length)
952  {
953  bestMatch = pattern;
954  }
955  }
956  }
957 
958  if (String.IsNullOrEmpty(bestMatch))
959  {
960  HTTPHandler = null;
961  return false;
962  }
963  else
964  {
965  HTTPHandler = m_HTTPHandlers[bestMatch];
966  return true;
967  }
968  }
969  }
970 
971 // private bool TryGetAgentHandler(OSHttpRequest request, OSHttpResponse response, out IHttpAgentHandler agentHandler)
972 // {
973 // agentHandler = null;
974 //
975 // lock (m_agentHandlers)
976 // {
977 // foreach (IHttpAgentHandler handler in m_agentHandlers.Values)
978 // {
979 // if (handler.Match(request, response))
980 // {
981 // agentHandler = handler;
982 // return true;
983 // }
984 // }
985 // }
986 //
987 // return false;
988 // }
989 
996  private byte[] HandleXmlRpcRequests(OSHttpRequest request, OSHttpResponse response)
997  {
998  String requestBody;
999 
1000  Stream requestStream = request.InputStream;
1001  Stream innerStream = null;
1002  try
1003  {
1004  if ((request.Headers["Content-Encoding"] == "gzip") || (request.Headers["X-Content-Encoding"] == "gzip"))
1005  {
1006  innerStream = requestStream;
1007  requestStream = new GZipStream(innerStream, System.IO.Compression.CompressionMode.Decompress);
1008  }
1009 
1010  using (StreamReader reader = new StreamReader(requestStream, Encoding.UTF8))
1011  {
1012  requestBody = reader.ReadToEnd();
1013  }
1014  }
1015  finally
1016  {
1017  if (innerStream != null)
1018  innerStream.Dispose();
1019  requestStream.Dispose();
1020  }
1021 
1022  //m_log.Debug(requestBody);
1023  requestBody = requestBody.Replace("<base64></base64>", "");
1024 
1025  string responseString = String.Empty;
1026  XmlRpcRequest xmlRprcRequest = null;
1027 
1028  bool gridproxy = false;
1029  if (requestBody.Contains("encoding=\"utf-8"))
1030  {
1031  int channelindx = -1;
1032  int optionsindx = requestBody.IndexOf(">options<");
1033  if(optionsindx >0)
1034  {
1035  channelindx = requestBody.IndexOf(">channel<");
1036  if (optionsindx < channelindx)
1037  gridproxy = true;
1038  }
1039  }
1040 
1041  try
1042  {
1043  xmlRprcRequest = (XmlRpcRequest) (new XmlRpcRequestDeserializer()).Deserialize(requestBody);
1044  }
1045  catch (XmlException e)
1046  {
1047  if (DebugLevel >= 1)
1048  {
1049  if (DebugLevel >= 2)
1050  m_log.Warn(
1051  string.Format(
1052  "[BASE HTTP SERVER]: Got XMLRPC request with invalid XML from {0}. XML was '{1}'. Sending blank response. Exception ",
1053  request.RemoteIPEndPoint, requestBody),
1054  e);
1055  else
1056  {
1057  m_log.WarnFormat(
1058  "[BASE HTTP SERVER]: Got XMLRPC request with invalid XML from {0}, length {1}. Sending blank response.",
1059  request.RemoteIPEndPoint, requestBody.Length);
1060  }
1061  }
1062  }
1063 
1064  if (xmlRprcRequest != null)
1065  {
1066  string methodName = xmlRprcRequest.MethodName;
1067  if (methodName != null)
1068  {
1069  xmlRprcRequest.Params.Add(request.RemoteIPEndPoint); // Param[1]
1070  XmlRpcResponse xmlRpcResponse;
1071 
1072  XmlRpcMethod method;
1073  bool methodWasFound;
1074  bool keepAlive = false;
1075  lock (m_rpcHandlers)
1076  {
1077  methodWasFound = m_rpcHandlers.TryGetValue(methodName, out method);
1078  if (methodWasFound)
1079  keepAlive = m_rpcHandlersKeepAlive[methodName];
1080  }
1081 
1082  if (methodWasFound)
1083  {
1084  xmlRprcRequest.Params.Add(request.Url); // Param[2]
1085 
1086  string xff = "X-Forwarded-For";
1087  string xfflower = xff.ToLower();
1088  foreach (string s in request.Headers.AllKeys)
1089  {
1090  if (s != null && s.Equals(xfflower))
1091  {
1092  xff = xfflower;
1093  break;
1094  }
1095  }
1096  xmlRprcRequest.Params.Add(request.Headers.Get(xff)); // Param[3]
1097 
1098  if (gridproxy)
1099  xmlRprcRequest.Params.Add("gridproxy"); // Param[4]
1100  try
1101  {
1102  xmlRpcResponse = method(xmlRprcRequest, request.RemoteIPEndPoint);
1103  }
1104  catch(Exception e)
1105  {
1106  string errorMessage
1107  = String.Format(
1108  "Requested method [{0}] from {1} threw exception: {2} {3}",
1109  methodName, request.RemoteIPEndPoint.Address, e.Message, e.StackTrace);
1110 
1111  m_log.ErrorFormat("[BASE HTTP SERVER]: {0}", errorMessage);
1112 
1113  // if the registered XmlRpc method threw an exception, we pass a fault-code along
1114  xmlRpcResponse = new XmlRpcResponse();
1115 
1116  // Code probably set in accordance with http://xmlrpc-epi.sourceforge.net/specs/rfc.fault_codes.php
1117  xmlRpcResponse.SetFault(-32603, errorMessage);
1118  }
1119 
1120  // if the method wasn't found, we can't determine KeepAlive state anyway, so lets do it only here
1121  response.KeepAlive = keepAlive;
1122  }
1123  else
1124  {
1125  xmlRpcResponse = new XmlRpcResponse();
1126 
1127  // Code set in accordance with http://xmlrpc-epi.sourceforge.net/specs/rfc.fault_codes.php
1128  xmlRpcResponse.SetFault(
1129  XmlRpcErrorCodes.SERVER_ERROR_METHOD,
1130  String.Format("Requested method [{0}] not found", methodName));
1131  }
1132 
1133  response.ContentType = "text/xml";
1134  using (MemoryStream outs = new MemoryStream())
1135  using (XmlTextWriter writer = new XmlTextWriter(outs, UTF8NoBOM))
1136  {
1137  writer.Formatting = Formatting.None;
1138  XmlRpcResponseSerializer.Singleton.Serialize(writer, xmlRpcResponse);
1139  writer.Flush();
1140  outs.Flush();
1141  outs.Position = 0;
1142  using (StreamReader sr = new StreamReader(outs))
1143  {
1144  responseString = sr.ReadToEnd();
1145  }
1146  }
1147  }
1148  else
1149  {
1150  //HandleLLSDRequests(request, response);
1151  response.ContentType = "text/plain";
1152  response.StatusCode = 404;
1153  response.StatusDescription = "Not Found";
1154  response.ProtocolVersion = "HTTP/1.0";
1155  responseString = "Not found";
1156  response.KeepAlive = false;
1157 
1158  m_log.ErrorFormat(
1159  "[BASE HTTP SERVER]: Handler not found for http request {0} {1}",
1160  request.HttpMethod, request.Url.PathAndQuery);
1161  }
1162  }
1163 
1164  byte[] buffer = Encoding.UTF8.GetBytes(responseString);
1165 
1166  response.SendChunked = false;
1167  response.ContentLength64 = buffer.Length;
1168  response.ContentEncoding = Encoding.UTF8;
1169 
1170  return buffer;
1171  }
1172 
1173  // JsonRpc (v2.0 only)
1174  // Batch requests not yet supported
1175  private byte[] HandleJsonRpcRequests(OSHttpRequest request, OSHttpResponse response)
1176  {
1177  Stream requestStream = request.InputStream;
1178  JsonRpcResponse jsonRpcResponse = new JsonRpcResponse();
1179  OSDMap jsonRpcRequest = null;
1180 
1181  try
1182  {
1183  jsonRpcRequest = (OSDMap)OSDParser.DeserializeJson(requestStream);
1184  }
1185  catch (LitJson.JsonException e)
1186  {
1187  jsonRpcResponse.Error.Code = ErrorCode.InternalError;
1188  jsonRpcResponse.Error.Message = e.Message;
1189  }
1190 
1191  requestStream.Close();
1192 
1193  if (jsonRpcRequest != null)
1194  {
1195  if (jsonRpcRequest.ContainsKey("jsonrpc") || jsonRpcRequest["jsonrpc"].AsString() == "2.0")
1196  {
1197  jsonRpcResponse.JsonRpc = "2.0";
1198 
1199  // If we have no id, then it's a "notification"
1200  if (jsonRpcRequest.ContainsKey("id"))
1201  {
1202  jsonRpcResponse.Id = jsonRpcRequest["id"].AsString();
1203  }
1204 
1205  string methodname = jsonRpcRequest["method"];
1206  JsonRPCMethod method;
1207 
1208  if (jsonRpcHandlers.ContainsKey(methodname))
1209  {
1210  lock(jsonRpcHandlers)
1211  {
1212  jsonRpcHandlers.TryGetValue(methodname, out method);
1213  }
1214  bool res = false;
1215  try
1216  {
1217  res = method(jsonRpcRequest, ref jsonRpcResponse);
1218  if(!res)
1219  {
1220  // The handler sent back an unspecified error
1221  if(jsonRpcResponse.Error.Code == 0)
1222  {
1223  jsonRpcResponse.Error.Code = ErrorCode.InternalError;
1224  }
1225  }
1226  }
1227  catch (Exception e)
1228  {
1229  string ErrorMessage = string.Format("[BASE HTTP SERVER]: Json-Rpc Handler Error method {0} - {1}", methodname, e.Message);
1230  m_log.Error(ErrorMessage);
1231  jsonRpcResponse.Error.Code = ErrorCode.InternalError;
1232  jsonRpcResponse.Error.Message = ErrorMessage;
1233  }
1234  }
1235  else // Error no hanlder defined for requested method
1236  {
1237  jsonRpcResponse.Error.Code = ErrorCode.InvalidRequest;
1238  jsonRpcResponse.Error.Message = string.Format ("No handler defined for {0}", methodname);
1239  }
1240  }
1241  else // not json-rpc 2.0 could be v1
1242  {
1243  jsonRpcResponse.Error.Code = ErrorCode.InvalidRequest;
1244  jsonRpcResponse.Error.Message = "Must be valid json-rpc 2.0 see: http://www.jsonrpc.org/specification";
1245 
1246  if (jsonRpcRequest.ContainsKey("id"))
1247  jsonRpcResponse.Id = jsonRpcRequest["id"].AsString();
1248  }
1249  }
1250 
1251  response.KeepAlive = true;
1252  string responseData = string.Empty;
1253 
1254  responseData = jsonRpcResponse.Serialize();
1255 
1256  byte[] buffer = Encoding.UTF8.GetBytes(responseData);
1257  return buffer;
1258  }
1259 
1260  private byte[] HandleLLSDRequests(OSHttpRequest request, OSHttpResponse response)
1261  {
1262  //m_log.Warn("[BASE HTTP SERVER]: We've figured out it's a LLSD Request");
1263  Stream requestStream = request.InputStream;
1264 
1265  Encoding encoding = Encoding.UTF8;
1266  StreamReader reader = new StreamReader(requestStream, encoding);
1267 
1268  string requestBody = reader.ReadToEnd();
1269  reader.Close();
1270  requestStream.Close();
1271 
1272  //m_log.DebugFormat("[OGP]: {0}:{1}", request.RawUrl, requestBody);
1273  // response.KeepAlive = true;
1274  response.KeepAlive = false;
1275 
1276  OSD llsdRequest = null;
1277  OSD llsdResponse = null;
1278 
1279  bool LegacyLLSDLoginLibOMV = (requestBody.Contains("passwd") && requestBody.Contains("mac") && requestBody.Contains("viewer_digest"));
1280 
1281  if (requestBody.Length == 0)
1282  // Get Request
1283  {
1284  requestBody = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><llsd><map><key>request</key><string>get</string></map></llsd>";
1285  }
1286  try
1287  {
1288  llsdRequest = OSDParser.Deserialize(requestBody);
1289  }
1290  catch (Exception ex)
1291  {
1292  m_log.Warn("[BASE HTTP SERVER]: Error - " + ex.Message);
1293  }
1294 
1295  if (llsdRequest != null)// && m_defaultLlsdHandler != null)
1296  {
1297  LLSDMethod llsdhandler = null;
1298 
1299  if (TryGetLLSDHandler(request.RawUrl, out llsdhandler) && !LegacyLLSDLoginLibOMV)
1300  {
1301  // we found a registered llsd handler to service this request
1302  llsdResponse = llsdhandler(request.RawUrl, llsdRequest, request.RemoteIPEndPoint.ToString());
1303  }
1304  else
1305  {
1306  // we didn't find a registered llsd handler to service this request
1307  // check if we have a default llsd handler
1308 
1309  if (m_defaultLlsdHandler != null)
1310  {
1311  // LibOMV path
1312  llsdResponse = m_defaultLlsdHandler(llsdRequest, request.RemoteIPEndPoint);
1313  }
1314  else
1315  {
1316  // Oops, no handler for this.. give em the failed message
1317  llsdResponse = GenerateNoLLSDHandlerResponse();
1318  }
1319  }
1320  }
1321  else
1322  {
1323  llsdResponse = GenerateNoLLSDHandlerResponse();
1324  }
1325 
1326  byte[] buffer = new byte[0];
1327 
1328  if (llsdResponse.ToString() == "shutdown404!")
1329  {
1330  response.ContentType = "text/plain";
1331  response.StatusCode = 404;
1332  response.StatusDescription = "Not Found";
1333  response.ProtocolVersion = "HTTP/1.0";
1334  buffer = Encoding.UTF8.GetBytes("Not found");
1335  }
1336  else
1337  {
1338  // Select an appropriate response format
1339  buffer = BuildLLSDResponse(request, response, llsdResponse);
1340  }
1341 
1342  response.SendChunked = false;
1343  response.ContentLength64 = buffer.Length;
1344  response.ContentEncoding = Encoding.UTF8;
1345  response.KeepAlive = true;
1346 
1347  return buffer;
1348  }
1349 
1350  private byte[] BuildLLSDResponse(OSHttpRequest request, OSHttpResponse response, OSD llsdResponse)
1351  {
1352  if (request.AcceptTypes != null && request.AcceptTypes.Length > 0)
1353  {
1354  foreach (string strAccept in request.AcceptTypes)
1355  {
1356  switch (strAccept)
1357  {
1358  case "application/llsd+xml":
1359  case "application/xml":
1360  case "text/xml":
1361  response.ContentType = strAccept;
1362  return OSDParser.SerializeLLSDXmlBytes(llsdResponse);
1363  case "application/llsd+json":
1364  case "application/json":
1365  response.ContentType = strAccept;
1366  return Encoding.UTF8.GetBytes(OSDParser.SerializeJsonString(llsdResponse));
1367  }
1368  }
1369  }
1370 
1371  if (!String.IsNullOrEmpty(request.ContentType))
1372  {
1373  switch (request.ContentType)
1374  {
1375  case "application/llsd+xml":
1376  case "application/xml":
1377  case "text/xml":
1378  response.ContentType = request.ContentType;
1379  return OSDParser.SerializeLLSDXmlBytes(llsdResponse);
1380  case "application/llsd+json":
1381  case "application/json":
1382  response.ContentType = request.ContentType;
1383  return Encoding.UTF8.GetBytes(OSDParser.SerializeJsonString(llsdResponse));
1384  }
1385  }
1386 
1387  // response.ContentType = "application/llsd+json";
1388  // return Util.UTF8.GetBytes(OSDParser.SerializeJsonString(llsdResponse));
1389  response.ContentType = "application/llsd+xml";
1390  return OSDParser.SerializeLLSDXmlBytes(llsdResponse);
1391  }
1392 
1398  private bool DoWeHaveALLSDHandler(string path)
1399  {
1400  string[] pathbase = path.Split('/');
1401  string searchquery = "/";
1402 
1403  if (pathbase.Length < 1)
1404  return false;
1405 
1406  for (int i = 1; i < pathbase.Length; i++)
1407  {
1408  searchquery += pathbase[i];
1409  if (pathbase.Length - 1 != i)
1410  searchquery += "/";
1411  }
1412 
1413  string bestMatch = null;
1414 
1415  lock (m_llsdHandlers)
1416  {
1417  foreach (string pattern in m_llsdHandlers.Keys)
1418  {
1419  if (searchquery.StartsWith(pattern) && searchquery.Length >= pattern.Length)
1420  bestMatch = pattern;
1421  }
1422  }
1423 
1424  // extra kicker to remove the default XMLRPC login case.. just in case..
1425  if (path != "/" && bestMatch == "/" && searchquery != "/")
1426  return false;
1427 
1428  if (path == "/")
1429  return false;
1430 
1431  if (String.IsNullOrEmpty(bestMatch))
1432  {
1433  return false;
1434  }
1435  else
1436  {
1437  return true;
1438  }
1439  }
1440 
1446  private bool DoWeHaveAHTTPHandler(string path)
1447  {
1448  string[] pathbase = path.Split('/');
1449  string searchquery = "/";
1450 
1451  if (pathbase.Length < 1)
1452  return false;
1453 
1454  for (int i = 1; i < pathbase.Length; i++)
1455  {
1456  searchquery += pathbase[i];
1457  if (pathbase.Length - 1 != i)
1458  searchquery += "/";
1459  }
1460 
1461  string bestMatch = null;
1462 
1463  //m_log.DebugFormat("[BASE HTTP HANDLER]: Checking if we have an HTTP handler for {0}", searchquery);
1464 
1465  lock (m_HTTPHandlers)
1466  {
1467  foreach (string pattern in m_HTTPHandlers.Keys)
1468  {
1469  if (searchquery.StartsWith(pattern) && searchquery.Length >= pattern.Length)
1470  {
1471  bestMatch = pattern;
1472  }
1473  }
1474 
1475  // extra kicker to remove the default XMLRPC login case.. just in case..
1476  if (path == "/")
1477  return false;
1478 
1479  if (String.IsNullOrEmpty(bestMatch))
1480  {
1481  return false;
1482  }
1483  else
1484  {
1485  return true;
1486  }
1487  }
1488  }
1489 
1490  private bool TryGetLLSDHandler(string path, out LLSDMethod llsdHandler)
1491  {
1492  llsdHandler = null;
1493  // Pull out the first part of the path
1494  // splitting the path by '/' means we'll get the following return..
1495  // {0}/{1}/{2}
1496  // where {0} isn't something we really control 100%
1497 
1498  string[] pathbase = path.Split('/');
1499  string searchquery = "/";
1500 
1501  if (pathbase.Length < 1)
1502  return false;
1503 
1504  for (int i=1; i<pathbase.Length; i++)
1505  {
1506  searchquery += pathbase[i];
1507  if (pathbase.Length-1 != i)
1508  searchquery += "/";
1509  }
1510 
1511  // while the matching algorithm below doesn't require it, we're expecting a query in the form
1512  //
1513  // [] = optional
1514  // /resource/UUID/action[/action]
1515  //
1516  // now try to get the closest match to the reigstered path
1517  // at least for OGP, registered path would probably only consist of the /resource/
1518 
1519  string bestMatch = null;
1520 
1521  lock (m_llsdHandlers)
1522  {
1523  foreach (string pattern in m_llsdHandlers.Keys)
1524  {
1525  if (searchquery.ToLower().StartsWith(pattern.ToLower()))
1526  {
1527  if (String.IsNullOrEmpty(bestMatch) || searchquery.Length > bestMatch.Length)
1528  {
1529  // You have to specifically register for '/' and to get it, you must specificaly request it
1530  //
1531  if (pattern == "/" && searchquery == "/" || pattern != "/")
1532  bestMatch = pattern;
1533  }
1534  }
1535  }
1536 
1537  if (String.IsNullOrEmpty(bestMatch))
1538  {
1539  llsdHandler = null;
1540  return false;
1541  }
1542  else
1543  {
1544  llsdHandler = m_llsdHandlers[bestMatch];
1545  return true;
1546  }
1547  }
1548  }
1549 
1550  private OSDMap GenerateNoLLSDHandlerResponse()
1551  {
1552  OSDMap map = new OSDMap();
1553  map["reason"] = OSD.FromString("LLSDRequest");
1554  map["message"] = OSD.FromString("No handler registered for LLSD Requests");
1555  map["login"] = OSD.FromString("false");
1556  return map;
1557  }
1558 
1559  public byte[] HandleHTTPRequest(OSHttpRequest request, OSHttpResponse response)
1560  {
1561 // m_log.DebugFormat(
1562 // "[BASE HTTP SERVER]: HandleHTTPRequest for request to {0}, method {1}",
1563 // request.RawUrl, request.HttpMethod);
1564 
1565  switch (request.HttpMethod)
1566  {
1567  case "OPTIONS":
1568  response.StatusCode = (int)OSHttpStatusCode.SuccessOk;
1569  return null;
1570 
1571  default:
1572  return HandleContentVerbs(request, response);
1573  }
1574  }
1575 
1576  private byte[] HandleContentVerbs(OSHttpRequest request, OSHttpResponse response)
1577  {
1578 // m_log.DebugFormat("[BASE HTTP SERVER]: HandleContentVerbs for request to {0}", request.RawUrl);
1579 
1580  // This is a test. There's a workable alternative.. as this way sucks.
1581  // We'd like to put this into a text file parhaps that's easily editable.
1582  //
1583  // For this test to work, I used the following secondlife.exe parameters
1584  // "C:\Program Files\SecondLifeWindLight\SecondLifeWindLight.exe" -settings settings_windlight.xml -channel "Second Life WindLight" -set SystemLanguage en-us -loginpage http://10.1.1.2:8002/?show_login_form=TRUE -loginuri http://10.1.1.2:8002 -user 10.1.1.2
1585  //
1586  // Even after all that, there's still an error, but it's a start.
1587  //
1588  // I depend on show_login_form being in the secondlife.exe parameters to figure out
1589  // to display the form, or process it.
1590  // a better way would be nifty.
1591 
1592  byte[] buffer;
1593 
1594  Stream requestStream = request.InputStream;
1595 
1596  Encoding encoding = Encoding.UTF8;
1597  StreamReader reader = new StreamReader(requestStream, encoding);
1598 
1599  string requestBody = reader.ReadToEnd();
1600  // avoid warning for now
1601  reader.ReadToEnd();
1602  reader.Close();
1603  requestStream.Close();
1604 
1605  Hashtable keysvals = new Hashtable();
1606  Hashtable headervals = new Hashtable();
1607 
1608  Hashtable requestVars = new Hashtable();
1609 
1610  string host = String.Empty;
1611 
1612  string[] querystringkeys = request.QueryString.AllKeys;
1613  string[] rHeaders = request.Headers.AllKeys;
1614 
1615  keysvals.Add("body", requestBody);
1616  keysvals.Add("uri", request.RawUrl);
1617  keysvals.Add("content-type", request.ContentType);
1618  keysvals.Add("http-method", request.HttpMethod);
1619 
1620  foreach (string queryname in querystringkeys)
1621  {
1622 // m_log.DebugFormat(
1623 // "[BASE HTTP SERVER]: Got query paremeter {0}={1}", queryname, request.QueryString[queryname]);
1624  keysvals.Add(queryname, request.QueryString[queryname]);
1625  requestVars.Add(queryname, keysvals[queryname]);
1626  }
1627 
1628  foreach (string headername in rHeaders)
1629  {
1630 // m_log.Debug("[BASE HTTP SERVER]: " + headername + "=" + request.Headers[headername]);
1631  headervals[headername] = request.Headers[headername];
1632  }
1633 
1634  if (headervals.Contains("Host"))
1635  {
1636  host = (string)headervals["Host"];
1637  }
1638 
1639  keysvals.Add("headers", headervals);
1640  keysvals.Add("querystringkeys", querystringkeys);
1641  keysvals.Add("requestvars", requestVars);
1642 // keysvals.Add("form", request.Form);
1643 
1644  if (keysvals.Contains("method"))
1645  {
1646 // m_log.Debug("[BASE HTTP SERVER]: Contains Method");
1647  string method = (string) keysvals["method"];
1648 // m_log.Debug("[BASE HTTP SERVER]: " + requestBody);
1649  GenericHTTPMethod requestprocessor;
1650  bool foundHandler = TryGetHTTPHandler(method, out requestprocessor);
1651  if (foundHandler)
1652  {
1653  Hashtable responsedata1 = requestprocessor(keysvals);
1654  buffer = DoHTTPGruntWork(responsedata1,response);
1655 
1656  //SendHTML500(response);
1657  }
1658  else
1659  {
1660 // m_log.Warn("[BASE HTTP SERVER]: Handler Not Found");
1661  buffer = SendHTML404(response, host);
1662  }
1663  }
1664  else
1665  {
1666  GenericHTTPMethod requestprocessor;
1667  bool foundHandler = TryGetHTTPHandlerPathBased(request.RawUrl, out requestprocessor);
1668  if (foundHandler)
1669  {
1670  Hashtable responsedata2 = requestprocessor(keysvals);
1671  buffer = DoHTTPGruntWork(responsedata2, response);
1672 
1673  //SendHTML500(response);
1674  }
1675  else
1676  {
1677 // m_log.Warn("[BASE HTTP SERVER]: Handler Not Found2");
1678  buffer = SendHTML404(response, host);
1679  }
1680  }
1681 
1682  return buffer;
1683  }
1684 
1685  private bool TryGetHTTPHandlerPathBased(string path, out GenericHTTPMethod httpHandler)
1686  {
1687  httpHandler = null;
1688  // Pull out the first part of the path
1689  // splitting the path by '/' means we'll get the following return..
1690  // {0}/{1}/{2}
1691  // where {0} isn't something we really control 100%
1692 
1693  string[] pathbase = path.Split('/');
1694  string searchquery = "/";
1695 
1696  if (pathbase.Length < 1)
1697  return false;
1698 
1699  for (int i = 1; i < pathbase.Length; i++)
1700  {
1701  searchquery += pathbase[i];
1702  if (pathbase.Length - 1 != i)
1703  searchquery += "/";
1704  }
1705 
1706  // while the matching algorithm below doesn't require it, we're expecting a query in the form
1707  //
1708  // [] = optional
1709  // /resource/UUID/action[/action]
1710  //
1711  // now try to get the closest match to the reigstered path
1712  // at least for OGP, registered path would probably only consist of the /resource/
1713 
1714  string bestMatch = null;
1715 
1716 // m_log.DebugFormat(
1717 // "[BASE HTTP HANDLER]: TryGetHTTPHandlerPathBased() looking for HTTP handler to match {0}", searchquery);
1718 
1719  lock (m_HTTPHandlers)
1720  {
1721  foreach (string pattern in m_HTTPHandlers.Keys)
1722  {
1723  if (searchquery.ToLower().StartsWith(pattern.ToLower()))
1724  {
1725  if (String.IsNullOrEmpty(bestMatch) || searchquery.Length > bestMatch.Length)
1726  {
1727  // You have to specifically register for '/' and to get it, you must specifically request it
1728  if (pattern == "/" && searchquery == "/" || pattern != "/")
1729  bestMatch = pattern;
1730  }
1731  }
1732  }
1733 
1734  if (String.IsNullOrEmpty(bestMatch))
1735  {
1736  httpHandler = null;
1737  return false;
1738  }
1739  else
1740  {
1741  if (bestMatch == "/" && searchquery != "/")
1742  return false;
1743 
1744  httpHandler = m_HTTPHandlers[bestMatch];
1745  return true;
1746  }
1747  }
1748  }
1749 
1750  internal byte[] DoHTTPGruntWork(Hashtable responsedata, OSHttpResponse response)
1751  {
1752  int responsecode;
1753  string responseString = String.Empty;
1754  byte[] responseData = null;
1755  string contentType;
1756 
1757  if (responsedata == null)
1758  {
1759  responsecode = 500;
1760  responseString = "No response could be obtained";
1761  contentType = "text/plain";
1762  responsedata = new Hashtable();
1763  }
1764  else
1765  {
1766  try
1767  {
1768  //m_log.Info("[BASE HTTP SERVER]: Doing HTTP Grunt work with response");
1769  responsecode = (int)responsedata["int_response_code"];
1770  if (responsedata["bin_response_data"] != null)
1771  responseData = (byte[])responsedata["bin_response_data"];
1772  else
1773  responseString = (string)responsedata["str_response_string"];
1774  contentType = (string)responsedata["content_type"];
1775  if (responseString == null)
1776  responseString = String.Empty;
1777  }
1778  catch
1779  {
1780  responsecode = 500;
1781  responseString = "No response could be obtained";
1782  contentType = "text/plain";
1783  responsedata = new Hashtable();
1784  }
1785  }
1786 
1787  if (responsedata.ContainsKey("error_status_text"))
1788  {
1789  response.StatusDescription = (string)responsedata["error_status_text"];
1790  }
1791  if (responsedata.ContainsKey("http_protocol_version"))
1792  {
1793  response.ProtocolVersion = (string)responsedata["http_protocol_version"];
1794  }
1795 /*
1796  if (responsedata.ContainsKey("keepalive"))
1797  {
1798  bool keepalive = (bool)responsedata["keepalive"];
1799  response.KeepAlive = keepalive;
1800  }
1801 
1802  if (responsedata.ContainsKey("reusecontext"))
1803  response.ReuseContext = (bool) responsedata["reusecontext"];
1804 */
1805  // disable this things
1806  response.KeepAlive = false;
1807  response.ReuseContext = false;
1808 
1809  // Cross-Origin Resource Sharing with simple requests
1810  if (responsedata.ContainsKey("access_control_allow_origin"))
1811  response.AddHeader("Access-Control-Allow-Origin", (string)responsedata["access_control_allow_origin"]);
1812 
1813  //Even though only one other part of the entire code uses HTTPHandlers, we shouldn't expect this
1814  //and should check for NullReferenceExceptions
1815 
1816  if (string.IsNullOrEmpty(contentType))
1817  {
1818  contentType = "text/html";
1819  }
1820 
1821 
1822 
1823  // The client ignores anything but 200 here for web login, so ensure that this is 200 for that
1824 
1825 
1826  response.StatusCode = responsecode;
1827 
1828  if (responsecode == (int)OSHttpStatusCode.RedirectMovedPermanently)
1829  {
1830  response.RedirectLocation = (string)responsedata["str_redirect_location"];
1831  response.StatusCode = responsecode;
1832  }
1833 
1834  response.AddHeader("Content-Type", contentType);
1835 
1836  if (responsedata.ContainsKey("headers"))
1837  {
1838  Hashtable headerdata = (Hashtable)responsedata["headers"];
1839 
1840  foreach (string header in headerdata.Keys)
1841  response.AddHeader(header, (string)headerdata[header]);
1842  }
1843 
1844  byte[] buffer;
1845 
1846  if (responseData != null)
1847  {
1848  buffer = responseData;
1849  }
1850  else
1851  {
1852  if (!(contentType.Contains("image")
1853  || contentType.Contains("x-shockwave-flash")
1854  || contentType.Contains("application/x-oar")
1855  || contentType.Contains("application/vnd.ll.mesh")))
1856  {
1857  // Text
1858  buffer = Encoding.UTF8.GetBytes(responseString);
1859  }
1860  else
1861  {
1862  // Binary!
1863  buffer = Convert.FromBase64String(responseString);
1864  }
1865 
1866  response.SendChunked = false;
1867  response.ContentLength64 = buffer.Length;
1868  response.ContentEncoding = Encoding.UTF8;
1869  }
1870 
1871  return buffer;
1872  }
1873 
1874  public byte[] SendHTML404(OSHttpResponse response, string host)
1875  {
1876  // I know this statuscode is dumb, but the client doesn't respond to 404s and 500s
1877  response.StatusCode = 404;
1878  response.AddHeader("Content-type", "text/html");
1879 
1880  string responseString = GetHTTP404(host);
1881  byte[] buffer = Encoding.UTF8.GetBytes(responseString);
1882 
1883  response.SendChunked = false;
1884  response.ContentLength64 = buffer.Length;
1885  response.ContentEncoding = Encoding.UTF8;
1886 
1887  return buffer;
1888  }
1889 
1890  public byte[] SendHTML500(OSHttpResponse response)
1891  {
1892  // I know this statuscode is dumb, but the client doesn't respond to 404s and 500s
1893  response.StatusCode = (int)OSHttpStatusCode.SuccessOk;
1894  response.AddHeader("Content-type", "text/html");
1895 
1896  string responseString = GetHTTP500();
1897  byte[] buffer = Encoding.UTF8.GetBytes(responseString);
1898 
1899  response.SendChunked = false;
1900  response.ContentLength64 = buffer.Length;
1901  response.ContentEncoding = Encoding.UTF8;
1902 
1903 
1904  return buffer;
1905  }
1906 
1907  public void Start()
1908  {
1909  Start(true);
1910  }
1911 
1919  public void Start(bool performPollResponsesAsync)
1920  {
1921  m_log.InfoFormat(
1922  "[BASE HTTP SERVER]: Starting {0} server on port {1}", UseSSL ? "HTTPS" : "HTTP", Port);
1923 
1924  try
1925  {
1926  //m_httpListener = new HttpListener();
1927 
1928  NotSocketErrors = 0;
1929  if (!m_ssl)
1930  {
1931  //m_httpListener.Prefixes.Add("http://+:" + m_port + "/");
1932  //m_httpListener.Prefixes.Add("http://10.1.1.5:" + m_port + "/");
1933  m_httpListener2 = CoolHTTPListener.Create(m_listenIPAddress, (int)m_port);
1934  m_httpListener2.ExceptionThrown += httpServerException;
1935  m_httpListener2.LogWriter = httpserverlog;
1936 
1937  // Uncomment this line in addition to those in HttpServerLogWriter
1938  // if you want more detailed trace information from the HttpServer
1939  //m_httpListener2.UseTraceLogs = true;
1940 
1941  //m_httpListener2.DisconnectHandler = httpServerDisconnectMonitor;
1942  }
1943  else
1944  {
1945  //m_httpListener.Prefixes.Add("https://+:" + (m_sslport) + "/");
1946  //m_httpListener.Prefixes.Add("http://+:" + m_port + "/");
1947  m_httpListener2 = CoolHTTPListener.Create(IPAddress.Any, (int)m_port, m_cert);
1948  m_httpListener2.ExceptionThrown += httpServerException;
1949  m_httpListener2.LogWriter = httpserverlog;
1950  }
1951 
1952  m_httpListener2.RequestReceived += OnRequest;
1953  //m_httpListener.Start();
1954  m_httpListener2.Start(64);
1955 
1956  // Long Poll Service Manager with 3 worker threads a 25 second timeout for no events
1957 
1958  PollServiceRequestManager = new PollServiceRequestManager(this, performPollResponsesAsync, 3, 25000);
1959  PollServiceRequestManager.Start();
1960 
1961  HTTPDRunning = true;
1962 
1963  //HttpListenerContext context;
1964  //while (true)
1965  //{
1966  // context = m_httpListener.GetContext();
1967  // ThreadPool.UnsafeQueueUserWorkItem(new WaitCallback(HandleRequest), context);
1968  // }
1969  }
1970  catch (Exception e)
1971  {
1972  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 + "?");
1974 
1975  // We want this exception to halt the entire server since in current configurations we aren't too
1976  // useful without inbound HTTP.
1977  throw e;
1978  }
1979 
1980  m_requestsProcessedStat
1981  = new Stat(
1982  "HTTPRequestsServed",
1983  "Number of inbound HTTP requests processed",
1984  "",
1985  "requests",
1986  "httpserver",
1987  Port.ToString(),
1988  StatType.Pull,
1989  MeasuresOfInterest.AverageChangeOverTime,
1990  stat => stat.Value = RequestNumber,
1991  StatVerbosity.Debug);
1992 
1993  StatsManager.RegisterStat(m_requestsProcessedStat);
1994  }
1995 
1996  public void httpServerDisconnectMonitor(IHttpClientContext source, SocketError err)
1997  {
1998  switch (err)
1999  {
2000  case SocketError.NotSocket:
2001  NotSocketErrors++;
2002 
2003  break;
2004  }
2005  }
2006 
2007  public void httpServerException(object source, Exception exception)
2008  {
2009  if (source.ToString() == "HttpServer.HttpListener" && exception.ToString().StartsWith("Mono.Security.Protocol.Tls.TlsException"))
2010  return;
2011  m_log.ErrorFormat("[BASE HTTP SERVER]: {0} had an exception {1}", source.ToString(), exception.ToString());
2012  /*
2013  if (HTTPDRunning)// && NotSocketErrors > 5)
2014  {
2015  Stop();
2016  Thread.Sleep(200);
2017  StartHTTP();
2018  m_log.Warn("[HTTPSERVER]: Died. Trying to kick.....");
2019  }
2020  */
2021  }
2022 
2023  public void Stop()
2024  {
2025  HTTPDRunning = false;
2026 
2027  StatsManager.DeregisterStat(m_requestsProcessedStat);
2028 
2029  try
2030  {
2031  PollServiceRequestManager.Stop();
2032 
2033  m_httpListener2.ExceptionThrown -= httpServerException;
2034  //m_httpListener2.DisconnectHandler = null;
2035 
2036  m_httpListener2.LogWriter = null;
2037  m_httpListener2.RequestReceived -= OnRequest;
2038  m_httpListener2.Stop();
2039  }
2040  catch (NullReferenceException)
2041  {
2042  m_log.Warn("[BASE HTTP SERVER]: Null Reference when stopping HttpServer.");
2043  }
2044  }
2045 
2046  public void RemoveStreamHandler(string httpMethod, string path)
2047  {
2048  string handlerKey = GetHandlerKey(httpMethod, path);
2049 
2050  //m_log.DebugFormat("[BASE HTTP SERVER]: Removing handler key {0}", handlerKey);
2051 
2052  lock (m_streamHandlers)
2053  m_streamHandlers.Remove(handlerKey);
2054  }
2055 
2056  public void RemoveHTTPHandler(string httpMethod, string path)
2057  {
2058  if (path == null) return; // Caps module isn't loaded, tries to remove handler where path = null
2059  lock (m_HTTPHandlers)
2060  {
2061  if (httpMethod != null && httpMethod.Length == 0)
2062  {
2063  m_HTTPHandlers.Remove(path);
2064  return;
2065  }
2066 
2067  m_HTTPHandlers.Remove(GetHandlerKey(httpMethod, path));
2068  }
2069  }
2070 
2071  public void RemovePollServiceHTTPHandler(string httpMethod, string path)
2072  {
2073  lock (m_pollHandlers)
2074  m_pollHandlers.Remove(path);
2075  }
2076 
2077 // public bool RemoveAgentHandler(string agent, IHttpAgentHandler handler)
2078 // {
2079 // lock (m_agentHandlers)
2080 // {
2081 // IHttpAgentHandler foundHandler;
2082 //
2083 // if (m_agentHandlers.TryGetValue(agent, out foundHandler) && foundHandler == handler)
2084 // {
2085 // m_agentHandlers.Remove(agent);
2086 // return true;
2087 // }
2088 // }
2089 //
2090 // return false;
2091 // }
2092 
2093  public void RemoveXmlRPCHandler(string method)
2094  {
2095  lock (m_rpcHandlers)
2096  m_rpcHandlers.Remove(method);
2097  }
2098 
2099  public void RemoveJsonRPCHandler(string method)
2100  {
2101  lock(jsonRpcHandlers)
2102  jsonRpcHandlers.Remove(method);
2103  }
2104 
2105  public bool RemoveLLSDHandler(string path, LLSDMethod handler)
2106  {
2107  lock (m_llsdHandlers)
2108  {
2109  LLSDMethod foundHandler;
2110 
2111  if (m_llsdHandlers.TryGetValue(path, out foundHandler) && foundHandler == handler)
2112  {
2113  m_llsdHandlers.Remove(path);
2114  return true;
2115  }
2116  }
2117 
2118  return false;
2119  }
2120 
2121  public string GetHTTP404(string host)
2122  {
2123  string file = Path.Combine(".", "http_404.html");
2124  if (!File.Exists(file))
2125  return getDefaultHTTP404(host);
2126 
2127  StreamReader sr = File.OpenText(file);
2128  string result = sr.ReadToEnd();
2129  sr.Close();
2130  return result;
2131  }
2132 
2133  public string GetHTTP500()
2134  {
2135  string file = Path.Combine(".", "http_500.html");
2136  if (!File.Exists(file))
2137  return getDefaultHTTP500();
2138 
2139  StreamReader sr = File.OpenText(file);
2140  string result = sr.ReadToEnd();
2141  sr.Close();
2142  return result;
2143  }
2144 
2145  // Fallback HTTP responses in case the HTTP error response files don't exist
2146  private static string getDefaultHTTP404(string host)
2147  {
2148  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><P>If you are trying to log-in, your link parameters should have: &quot;-loginpage http://" + host + "/?method=login -loginuri http://" + host + "/&quot; in your link </P></BODY></HTML>";
2149  }
2150 
2151  private static string getDefaultHTTP500()
2152  {
2153  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>";
2154  }
2155  }
2156 
2158  {
2159  public IHttpClientContext context = null;
2160  public IHttpRequest req = null;
2161  public OSHttpRequest oreq = null;
2162  public OSHttpResponse oresp = null;
2163 
2164  public HttpServerContextObj(IHttpClientContext contxt, IHttpRequest reqs)
2165  {
2166  context = contxt;
2167  req = reqs;
2168  }
2169 
2171  {
2172  oreq = osreq;
2173  oresp = osresp;
2174  }
2175  }
2176 
2184  public class HttpServerLogWriter : ILogWriter
2185  {
2186 // private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
2187 
2188  public void Write(object source, LogPrio priority, string message)
2189  {
2190  /*
2191  switch (priority)
2192  {
2193  case LogPrio.Trace:
2194  m_log.DebugFormat("[{0}]: {1}", source, message);
2195  break;
2196  case LogPrio.Debug:
2197  m_log.DebugFormat("[{0}]: {1}", source, message);
2198  break;
2199  case LogPrio.Error:
2200  m_log.ErrorFormat("[{0}]: {1}", source, message);
2201  break;
2202  case LogPrio.Info:
2203  m_log.InfoFormat("[{0}]: {1}", source, message);
2204  break;
2205  case LogPrio.Warning:
2206  m_log.WarnFormat("[{0}]: {1}", source, message);
2207  break;
2208  case LogPrio.Fatal:
2209  m_log.ErrorFormat("[{0}]: FATAL! - {1}", source, message);
2210  break;
2211  default:
2212  break;
2213  }
2214  */
2215 
2216  return;
2217  }
2218  }
2219 }
bool RemoveLLSDHandler(string path, LLSDMethod handler)
bool AddHTTPHandler(string methodName, GenericHTTPMethod handler)
Add a handler for an HTTP request.
bool AddLLSDHandler(string path, LLSDMethod handler)
Adds a LLSD handler, yay.
HttpServer.LogPrio LogPrio
void RemovePollServiceHTTPHandler(string httpMethod, string path)
void Write(object source, LogPrio priority, string message)
byte[] SendHTML404(OSHttpResponse response, string host)
delegate OSD DefaultLLSDMethod(OSD request, IPEndPoint client)
delegate bool JsonRPCMethod(OSDMap jsonRpcRequest, ref JsonRpcResponse response)
HttpServer.HttpListener CoolHTTPListener
XmlRpcMethod GetXmlRPCHandler(string method)
Gets the XML RPC handler for given method name
This class implements websockets. It grabs the network context from C::Webserver and utilizes it dire...
OSHttpResponse is the OpenSim representation of an HTTP response.
byte[] HandleHTTPRequest(OSHttpRequest request, OSHttpResponse response)
void httpServerException(object source, Exception exception)
OpenMetaverse.StructuredData.OSDMap OSDMap
void Start(bool performPollResponsesAsync)
Start the http server
Holds individual statistic details
Definition: Stat.cs:41
HttpServerContextObj(OSHttpRequest osreq, OSHttpResponse osresp)
bool AddXmlRPCHandler(string method, XmlRpcMethod handler, bool keepAlive)
Ionic.Zlib.GZipStream GZipStream
void RemoveHTTPHandler(string httpMethod, string path)
Remove an HTTP handler
bool AddJsonRPCHandler(string method, JsonRPCMethod handler)
Interface to OpenSimulator's built in HTTP server. Use this to register handlers (http, llsd, xmlrpc, etc.) for given URLs.
Definition: IHttpServer.cs:36
Relays HttpServer log messages to our own logging mechanism.
bool AddXmlRPCHandler(string method, XmlRpcMethod handler)
bool SetDefaultLLSDHandler(DefaultLLSDMethod handler)
BaseHttpServer(uint port, bool ssl, uint sslport, string CN)
void AddStreamHandler(IRequestHandler handler)
Add a stream handler to the http server. If the handler already exists, then nothing happens...
bool AddPollServiceHTTPHandler(string methodName, PollServiceEventArgs args)
delegate XmlRpcResponse XmlRpcMethod(XmlRpcRequest request, IPEndPoint client)
OpenMetaverse.StructuredData.OSD OSD
BaseHttpServer(uint port, bool ssl, string CPath, string CPass)
void OnRequest(object source, RequestEventArgs args)
void RemoveStreamHandler(string httpMethod, string path)
delegate Hashtable GenericHTTPMethod(Hashtable request)
HttpServerContextObj(IHttpClientContext contxt, IHttpRequest reqs)
void AddWebSocketHandler(string servicepath, WebSocketRequestDelegate handler)
virtual void HandleRequest(OSHttpRequest request, OSHttpResponse response)
This methods is the start of incoming HTTP request handling.
void AddHeader(string key, string value)
Add a header field and content to the response.
System.Net.HttpListener HttpListener
delegate OSD LLSDMethod(string path, OSD request, string endpoint)
void httpServerDisconnectMonitor(IHttpClientContext source, SocketError err)
OSHttpStatusCode
HTTP status codes (almost) as defined by W3C in http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html and IETF in http://tools.ietf.org/html/rfc6585