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