clockwerk-opensim – Blame information for rev 1

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