2009-05-04 20:19:21 +00:00
/ *
* Copyright ( c ) Contributors , http : //opensimulator.org/
* See CONTRIBUTORS . TXT for a full list of copyright holders .
*
* Redistribution and use in source and binary forms , with or without
* modification , are permitted provided that the following conditions are met :
* * Redistributions of source code must retain the above copyright
* notice , this list of conditions and the following disclaimer .
* * Redistributions in binary form must reproduce the above copyright
* notice , this list of conditions and the following disclaimer in the
* documentation and / or other materials provided with the distribution .
2009-06-01 06:37:14 +00:00
* * Neither the name of the OpenSimulator Project nor the
2009-05-04 20:19:21 +00:00
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission .
*
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ` ` AS IS ' ' AND ANY
* EXPRESS OR IMPLIED WARRANTIES , INCLUDING , BUT NOT LIMITED TO , THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED . IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT , INDIRECT , INCIDENTAL , SPECIAL , EXEMPLARY , OR CONSEQUENTIAL DAMAGES
* ( INCLUDING , BUT NOT LIMITED TO , PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES ;
* LOSS OF USE , DATA , OR PROFITS ; OR BUSINESS INTERRUPTION ) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY , WHETHER IN CONTRACT , STRICT LIABILITY , OR TORT
* ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE .
* /
using System ;
using System.Collections ;
using System.Collections.Generic ;
2010-09-04 00:18:53 +00:00
using System.Collections.Specialized ;
2009-05-04 20:19:21 +00:00
using System.IO ;
using System.Net ;
using System.Net.Sockets ;
2011-05-01 18:44:09 +00:00
using System.Security.Cryptography.X509Certificates ;
2009-05-04 20:19:21 +00:00
using System.Reflection ;
using System.Globalization ;
using System.Text ;
using System.Threading ;
using System.Xml ;
using HttpServer ;
using log4net ;
using Nwc.XmlRpc ;
using OpenMetaverse.StructuredData ;
using CoolHTTPListener = HttpServer . HttpListener ;
using HttpListener = System . Net . HttpListener ;
2010-03-16 22:58:12 +00:00
using LogPrio = HttpServer . LogPrio ;
2012-07-25 22:27:00 +00:00
using OpenSim.Framework.Monitoring ;
2009-05-04 20:19:21 +00:00
namespace OpenSim.Framework.Servers.HttpServer
{
public class BaseHttpServer : IHttpServer
{
private static readonly ILog m_log = LogManager . GetLogger ( MethodBase . GetCurrentMethod ( ) . DeclaringType ) ;
private HttpServerLogWriter httpserverlog = new HttpServerLogWriter ( ) ;
2010-09-12 17:43:49 +00:00
2012-09-20 22:18:19 +00:00
/// <summary>
/// Gets or sets the debug level.
/// </summary>
/// <value>
/// See MainServer.DebugLevel.
/// </value>
2012-06-15 00:24:36 +00:00
public int DebugLevel { get ; set ; }
2012-09-20 23:09:17 +00:00
/// <summary>
/// Request number for diagnostic purposes.
/// </summary>
/// <remarks>
/// This is an internal number. In some debug situations an external number may also be supplied in the
/// opensim-request-id header but we are not currently logging this.
/// </remarks>
public int RequestNumber { get ; private set ; }
2009-05-04 20:19:21 +00:00
private volatile int NotSocketErrors = 0 ;
public volatile bool HTTPDRunning = false ;
// protected HttpListener m_httpListener;
protected CoolHTTPListener m_httpListener2 ;
protected Dictionary < string , XmlRpcMethod > m_rpcHandlers = new Dictionary < string , XmlRpcMethod > ( ) ;
protected Dictionary < string , bool > m_rpcHandlersKeepAlive = new Dictionary < string , bool > ( ) ;
protected DefaultLLSDMethod m_defaultLlsdHandler = null ; // <-- Moving away from the monolithic.. and going to /registered/
protected Dictionary < string , LLSDMethod > m_llsdHandlers = new Dictionary < string , LLSDMethod > ( ) ;
protected Dictionary < string , IRequestHandler > m_streamHandlers = new Dictionary < string , IRequestHandler > ( ) ;
protected Dictionary < string , GenericHTTPMethod > m_HTTPHandlers = new Dictionary < string , GenericHTTPMethod > ( ) ;
2012-09-20 23:29:13 +00:00
// protected Dictionary<string, IHttpAgentHandler> m_agentHandlers = new Dictionary<string, IHttpAgentHandler>();
2009-07-29 02:15:45 +00:00
protected Dictionary < string , PollServiceEventArgs > m_pollHandlers =
new Dictionary < string , PollServiceEventArgs > ( ) ;
2009-05-04 20:19:21 +00:00
protected uint m_port ;
protected uint m_sslport ;
protected bool m_ssl ;
2011-05-01 18:44:09 +00:00
private X509Certificate2 m_cert ;
2009-05-04 20:19:21 +00:00
protected bool m_firstcaps = true ;
protected string m_SSLCommonName = "" ;
2009-05-30 16:13:40 +00:00
protected IPAddress m_listenIPAddress = IPAddress . Any ;
2009-07-29 02:15:45 +00:00
private PollServiceRequestManager m_PollServiceManager ;
2009-05-04 20:19:21 +00:00
public uint SSLPort
{
get { return m_sslport ; }
}
public string SSLCommonName
{
get { return m_SSLCommonName ; }
}
public uint Port
{
get { return m_port ; }
}
public bool UseSSL
{
get { return m_ssl ; }
}
2009-05-30 16:13:40 +00:00
public IPAddress ListenIPAddress
{
get { return m_listenIPAddress ; }
set { m_listenIPAddress = value ; }
}
2009-05-04 20:19:21 +00:00
public BaseHttpServer ( uint port )
{
m_port = port ;
}
public BaseHttpServer ( uint port , bool ssl ) : this ( port )
{
2009-09-30 16:00:09 +00:00
m_ssl = ssl ;
2009-05-04 20:19:21 +00:00
}
public BaseHttpServer ( uint port , bool ssl , uint sslport , string CN ) : this ( port , ssl )
{
if ( m_ssl )
{
m_sslport = sslport ;
}
}
2011-05-01 18:44:09 +00:00
public BaseHttpServer ( uint port , bool ssl , string CPath , string CPass ) : this ( port , ssl )
{
if ( m_ssl )
{
m_cert = new X509Certificate2 ( CPath , CPass ) ;
}
}
2009-05-04 20:19:21 +00:00
/// <summary>
/// Add a stream handler to the http server. If the handler already exists, then nothing happens.
/// </summary>
/// <param name="handler"></param>
public void AddStreamHandler ( IRequestHandler handler )
{
string httpMethod = handler . HttpMethod ;
string path = handler . Path ;
string handlerKey = GetHandlerKey ( httpMethod , path ) ;
lock ( m_streamHandlers )
{
if ( ! m_streamHandlers . ContainsKey ( handlerKey ) )
{
// m_log.DebugFormat("[BASE HTTP SERVER]: Adding handler key {0}", handlerKey);
m_streamHandlers . Add ( handlerKey , handler ) ;
}
}
}
2012-05-03 00:45:49 +00:00
public List < string > GetStreamHandlerKeys ( )
2011-02-06 01:57:30 +00:00
{
2011-08-22 00:58:50 +00:00
lock ( m_streamHandlers )
return new List < string > ( m_streamHandlers . Keys ) ;
2011-02-06 01:57:30 +00:00
}
2009-05-04 20:19:21 +00:00
private static string GetHandlerKey ( string httpMethod , string path )
{
return httpMethod + ":" + path ;
}
public bool AddXmlRPCHandler ( string method , XmlRpcMethod handler )
{
return AddXmlRPCHandler ( method , handler , true ) ;
}
public bool AddXmlRPCHandler ( string method , XmlRpcMethod handler , bool keepAlive )
{
lock ( m_rpcHandlers )
{
m_rpcHandlers [ method ] = handler ;
2009-09-30 16:00:09 +00:00
m_rpcHandlersKeepAlive [ method ] = keepAlive ; // default
2009-05-04 20:19:21 +00:00
}
2010-09-12 17:43:49 +00:00
2009-05-04 20:19:21 +00:00
return true ;
}
public XmlRpcMethod GetXmlRPCHandler ( string method )
{
lock ( m_rpcHandlers )
{
if ( m_rpcHandlers . ContainsKey ( method ) )
{
return m_rpcHandlers [ method ] ;
}
else
{
return null ;
}
}
}
2011-02-06 01:57:30 +00:00
public List < string > GetXmlRpcHandlerKeys ( )
{
2011-08-22 00:43:34 +00:00
lock ( m_rpcHandlers )
return new List < string > ( m_rpcHandlers . Keys ) ;
2011-02-06 01:57:30 +00:00
}
2009-05-04 20:19:21 +00:00
public bool AddHTTPHandler ( string methodName , GenericHTTPMethod handler )
{
//m_log.DebugFormat("[BASE HTTP SERVER]: Registering {0}", methodName);
2010-09-12 17:43:49 +00:00
2009-05-04 20:19:21 +00:00
lock ( m_HTTPHandlers )
{
if ( ! m_HTTPHandlers . ContainsKey ( methodName ) )
{
m_HTTPHandlers . Add ( methodName , handler ) ;
return true ;
}
}
//must already have a handler for that path so return false
return false ;
}
2011-02-06 01:57:30 +00:00
public List < string > GetHTTPHandlerKeys ( )
{
2011-08-22 00:59:40 +00:00
lock ( m_HTTPHandlers )
return new List < string > ( m_HTTPHandlers . Keys ) ;
2011-02-06 01:57:30 +00:00
}
2011-12-07 12:28:42 +00:00
public bool AddPollServiceHTTPHandler ( string methodName , PollServiceEventArgs args )
2009-07-29 02:15:45 +00:00
{
lock ( m_pollHandlers )
{
2009-08-01 05:11:47 +00:00
if ( ! m_pollHandlers . ContainsKey ( methodName ) )
2009-07-29 02:15:45 +00:00
{
2011-12-07 12:28:42 +00:00
m_pollHandlers . Add ( methodName , args ) ;
return true ;
2009-07-29 02:15:45 +00:00
}
}
2010-09-12 17:43:49 +00:00
return false ;
2009-07-29 02:15:45 +00:00
}
2011-02-06 01:57:30 +00:00
public List < string > GetPollServiceHandlerKeys ( )
{
2011-08-22 01:10:45 +00:00
lock ( m_pollHandlers )
return new List < string > ( m_pollHandlers . Keys ) ;
2011-02-06 01:57:30 +00:00
}
2012-09-20 23:29:13 +00:00
// // Note that the agent string is provided simply to differentiate
// // the handlers - it is NOT required to be an actual agent header
// // value.
// public bool AddAgentHandler(string agent, IHttpAgentHandler handler)
// {
// lock (m_agentHandlers)
// {
// if (!m_agentHandlers.ContainsKey(agent))
// {
// m_agentHandlers.Add(agent, handler);
// return true;
// }
// }
/ /
// //must already have a handler for that path so return false
// return false;
// }
/ /
// public List<string> GetAgentHandlerKeys()
// {
// lock (m_agentHandlers)
// return new List<string>(m_agentHandlers.Keys);
// }
2011-02-06 01:57:30 +00:00
2009-05-04 20:19:21 +00:00
public bool AddLLSDHandler ( string path , LLSDMethod handler )
{
lock ( m_llsdHandlers )
{
if ( ! m_llsdHandlers . ContainsKey ( path ) )
{
m_llsdHandlers . Add ( path , handler ) ;
return true ;
}
}
return false ;
}
2011-02-06 01:57:30 +00:00
public List < string > GetLLSDHandlerKeys ( )
{
2011-08-22 00:52:08 +00:00
lock ( m_llsdHandlers )
return new List < string > ( m_llsdHandlers . Keys ) ;
2011-02-06 01:57:30 +00:00
}
2009-05-04 20:19:21 +00:00
public bool SetDefaultLLSDHandler ( DefaultLLSDMethod handler )
{
m_defaultLlsdHandler = handler ;
return true ;
}
2009-07-21 06:47:29 +00:00
private void OnRequest ( object source , RequestEventArgs args )
{
2012-09-20 23:09:17 +00:00
RequestNumber + + ;
2009-12-15 16:34:27 +00:00
try
2009-07-29 02:15:45 +00:00
{
2009-12-15 16:34:27 +00:00
IHttpClientContext context = ( IHttpClientContext ) source ;
IHttpRequest request = args . Request ;
2010-09-12 17:43:49 +00:00
2009-12-15 16:34:27 +00:00
PollServiceEventArgs psEvArgs ;
2010-09-12 17:43:49 +00:00
2009-12-15 16:34:27 +00:00
if ( TryGetPollServiceHTTPHandler ( request . UriPath . ToString ( ) , out psEvArgs ) )
2009-09-22 05:19:02 +00:00
{
2009-12-15 16:34:27 +00:00
PollServiceHttpRequest psreq = new PollServiceHttpRequest ( psEvArgs , context , request ) ;
2010-09-12 17:43:49 +00:00
2009-12-15 16:34:27 +00:00
if ( psEvArgs . Request ! = null )
2009-09-22 05:19:02 +00:00
{
2009-12-15 16:34:27 +00:00
OSHttpRequest req = new OSHttpRequest ( context , request ) ;
2010-09-12 17:43:49 +00:00
2009-12-15 16:34:27 +00:00
Stream requestStream = req . InputStream ;
2010-09-12 17:43:49 +00:00
2009-12-15 16:34:27 +00:00
Encoding encoding = Encoding . UTF8 ;
StreamReader reader = new StreamReader ( requestStream , encoding ) ;
2010-09-12 17:43:49 +00:00
2009-12-15 16:34:27 +00:00
string requestBody = reader . ReadToEnd ( ) ;
2010-09-12 17:43:49 +00:00
2009-12-15 16:34:27 +00:00
Hashtable keysvals = new Hashtable ( ) ;
Hashtable headervals = new Hashtable ( ) ;
2010-09-12 17:43:49 +00:00
2009-12-15 16:34:27 +00:00
string [ ] querystringkeys = req . QueryString . AllKeys ;
string [ ] rHeaders = req . Headers . AllKeys ;
2010-09-12 17:43:49 +00:00
2009-12-15 16:34:27 +00:00
keysvals . Add ( "body" , requestBody ) ;
keysvals . Add ( "uri" , req . RawUrl ) ;
keysvals . Add ( "content-type" , req . ContentType ) ;
keysvals . Add ( "http-method" , req . HttpMethod ) ;
2010-09-12 17:43:49 +00:00
2009-12-15 16:34:27 +00:00
foreach ( string queryname in querystringkeys )
{
keysvals . Add ( queryname , req . QueryString [ queryname ] ) ;
}
2010-09-12 17:43:49 +00:00
2009-12-15 16:34:27 +00:00
foreach ( string headername in rHeaders )
{
headervals [ headername ] = req . Headers [ headername ] ;
}
2010-09-12 17:43:49 +00:00
2010-03-16 22:58:12 +00:00
keysvals . Add ( "headers" , headervals ) ;
2009-12-15 16:34:27 +00:00
keysvals . Add ( "querystringkeys" , querystringkeys ) ;
2010-09-12 17:43:49 +00:00
2009-12-15 16:34:27 +00:00
psEvArgs . Request ( psreq . RequestID , keysvals ) ;
2009-09-22 05:19:02 +00:00
}
2010-09-12 17:43:49 +00:00
2009-12-15 16:34:27 +00:00
m_PollServiceManager . Enqueue ( psreq ) ;
}
else
{
OnHandleRequestIOThread ( context , request ) ;
2009-09-22 05:19:02 +00:00
}
2009-07-29 02:15:45 +00:00
}
2009-12-15 16:34:27 +00:00
catch ( Exception e )
2009-07-29 02:15:45 +00:00
{
2012-04-23 12:27:04 +00:00
m_log . Error ( String . Format ( "[BASE HTTP SERVER]: OnRequest() failed: {0} " , e . Message ) , e ) ;
2009-07-29 02:15:45 +00:00
}
2009-07-21 06:47:29 +00:00
}
2009-05-04 20:19:21 +00:00
public void OnHandleRequestIOThread ( IHttpClientContext context , IHttpRequest request )
{
OSHttpRequest req = new OSHttpRequest ( context , request ) ;
2009-07-29 20:32:54 +00:00
OSHttpResponse resp = new OSHttpResponse ( new HttpResponse ( context , request ) , context ) ;
2009-05-04 20:19:21 +00:00
HandleRequest ( req , resp ) ;
2010-08-06 17:57:52 +00:00
// !!!HACK ALERT!!!
// There seems to be a bug in the underlying http code that makes subsequent requests
// come up with trash in Accept headers. Until that gets fixed, we're cleaning them up here.
if ( request . AcceptTypes ! = null )
for ( int i = 0 ; i < request . AcceptTypes . Length ; i + + )
request . AcceptTypes [ i ] = string . Empty ;
2009-05-04 20:19:21 +00:00
}
2009-12-23 17:33:54 +00:00
// public void ConvertIHttpClientContextToOSHttp(object stateinfo)
// {
// HttpServerContextObj objstate = (HttpServerContextObj)stateinfo;
2009-05-04 20:19:21 +00:00
2009-12-23 17:33:54 +00:00
// OSHttpRequest request = objstate.oreq;
// OSHttpResponse resp = objstate.oresp;
2009-05-04 20:19:21 +00:00
2009-12-23 17:33:54 +00:00
// HandleRequest(request,resp);
// }
2009-05-04 20:19:21 +00:00
2010-08-30 21:33:45 +00:00
/// <summary>
/// This methods is the start of incoming HTTP request handling.
/// </summary>
/// <param name="request"></param>
/// <param name="response"></param>
2009-05-04 20:19:21 +00:00
public virtual void HandleRequest ( OSHttpRequest request , OSHttpResponse response )
{
2011-03-14 11:56:50 +00:00
if ( request . HttpMethod = = String . Empty ) // Can't handle empty requests, not wasting a thread
{
try
{
SendHTML500 ( response ) ;
}
catch
{
}
return ;
}
string requestMethod = request . HttpMethod ;
string uriString = request . RawUrl ;
2012-06-12 23:03:44 +00:00
int requestStartTick = Environment . TickCount ;
// Will be adjusted later on.
int requestEndTick = requestStartTick ;
2011-01-05 22:32:00 +00:00
2012-05-03 00:45:49 +00:00
IRequestHandler requestHandler = null ;
2009-05-04 20:19:21 +00:00
try
{
2011-01-05 22:32:00 +00:00
// OpenSim.Framework.WebUtil.OSHeaderRequestID
2011-08-22 00:45:46 +00:00
// if (request.Headers["opensim-request-id"] != null)
// reqnum = String.Format("{0}:{1}",request.RemoteIPEndPoint,request.Headers["opensim-request-id"]);
2011-06-12 22:37:42 +00:00
//m_log.DebugFormat("[BASE HTTP SERVER]: <{0}> handle request for {1}",reqnum,request.RawUrl);
2010-09-12 17:43:49 +00:00
2009-05-04 20:19:21 +00:00
Thread . CurrentThread . CurrentCulture = new CultureInfo ( "en-US" , true ) ;
2010-09-12 17:43:49 +00:00
2012-09-20 23:29:13 +00:00
// // This is the REST agent interface. We require an agent to properly identify
// // itself. If the REST handler recognizes the prefix it will attempt to
// // satisfy the request. If it is not recognizable, and no damage has occurred
// // the request can be passed through to the other handlers. This is a low
// // probability event; if a request is matched it is normally expected to be
// // handled
// IHttpAgentHandler agentHandler;
/ /
// if (TryGetAgentHandler(request, response, out agentHandler))
// {
// if (HandleAgentRequest(agentHandler, request, response))
// {
// requestEndTick = Environment.TickCount;
// return;
// }
// }
2009-09-22 04:24:22 +00:00
//response.KeepAlive = true;
response . SendChunked = false ;
2009-05-04 20:19:21 +00:00
string path = request . RawUrl ;
string handlerKey = GetHandlerKey ( request . HttpMethod , path ) ;
2012-06-12 23:03:44 +00:00
byte [ ] buffer = null ;
2009-05-04 20:19:21 +00:00
if ( TryGetStreamHandler ( handlerKey , out requestHandler ) )
{
2012-06-14 22:46:09 +00:00
if ( DebugLevel > = 3 )
2012-09-11 20:48:02 +00:00
LogIncomingToStreamHandler ( request , requestHandler ) ;
2011-11-29 16:15:52 +00:00
2009-09-22 04:24:22 +00:00
response . ContentType = requestHandler . ContentType ; // Lets do this defaulting before in case handler has varying content type.
2009-09-21 18:46:29 +00:00
2009-05-04 20:19:21 +00:00
if ( requestHandler is IStreamedRequestHandler )
{
IStreamedRequestHandler streamedRequestHandler = requestHandler as IStreamedRequestHandler ;
buffer = streamedRequestHandler . Handle ( path , request . InputStream , request , response ) ;
}
else if ( requestHandler is IGenericHTTPHandler )
{
2010-10-20 06:36:59 +00:00
//m_log.Debug("[BASE HTTP SERVER]: Found Caps based HTTP Handler");
2009-05-04 20:19:21 +00:00
IGenericHTTPHandler HTTPRequestHandler = requestHandler as IGenericHTTPHandler ;
Stream requestStream = request . InputStream ;
Encoding encoding = Encoding . UTF8 ;
StreamReader reader = new StreamReader ( requestStream , encoding ) ;
string requestBody = reader . ReadToEnd ( ) ;
reader . Close ( ) ;
2009-07-29 02:15:45 +00:00
//requestStream.Close();
2009-05-04 20:19:21 +00:00
Hashtable keysvals = new Hashtable ( ) ;
Hashtable headervals = new Hashtable ( ) ;
//string host = String.Empty;
string [ ] querystringkeys = request . QueryString . AllKeys ;
string [ ] rHeaders = request . Headers . AllKeys ;
foreach ( string queryname in querystringkeys )
{
keysvals . Add ( queryname , request . QueryString [ queryname ] ) ;
}
foreach ( string headername in rHeaders )
{
2010-10-20 06:36:59 +00:00
//m_log.Warn("[HEADER]: " + headername + "=" + request.Headers[headername]);
2009-05-04 20:19:21 +00:00
headervals [ headername ] = request . Headers [ headername ] ;
}
// if (headervals.Contains("Host"))
// {
// host = (string)headervals["Host"];
// }
keysvals . Add ( "requestbody" , requestBody ) ;
2009-09-21 19:21:01 +00:00
keysvals . Add ( "headers" , headervals ) ;
2009-05-04 20:19:21 +00:00
if ( keysvals . Contains ( "method" ) )
{
//m_log.Warn("[HTTP]: Contains Method");
//string method = (string)keysvals["method"];
//m_log.Warn("[HTTP]: " + requestBody);
}
2012-06-12 23:03:44 +00:00
buffer = DoHTTPGruntWork ( HTTPRequestHandler . Handle ( path , keysvals ) , response ) ;
2009-05-04 20:19:21 +00:00
}
else
{
IStreamHandler streamHandler = ( IStreamHandler ) requestHandler ;
using ( MemoryStream memoryStream = new MemoryStream ( ) )
{
streamHandler . Handle ( path , request . InputStream , memoryStream , request , response ) ;
memoryStream . Flush ( ) ;
buffer = memoryStream . ToArray ( ) ;
}
}
}
2012-06-12 23:03:44 +00:00
else
2009-05-04 20:19:21 +00:00
{
2012-06-12 23:03:44 +00:00
switch ( request . ContentType )
2009-05-04 20:19:21 +00:00
{
2012-06-12 23:03:44 +00:00
case null :
case "text/html" :
2012-06-14 22:46:09 +00:00
if ( DebugLevel > = 3 )
2012-10-22 23:39:59 +00:00
LogIncomingToContentTypeHandler ( request ) ;
2012-06-12 23:03:44 +00:00
buffer = HandleHTTPRequest ( request , response ) ;
break ;
case "application/llsd+xml" :
case "application/xml+llsd" :
case "application/llsd+json" :
2012-06-14 22:46:09 +00:00
if ( DebugLevel > = 3 )
2012-10-22 23:39:59 +00:00
LogIncomingToContentTypeHandler ( request ) ;
2012-06-12 23:03:44 +00:00
buffer = HandleLLSDRequests ( request , response ) ;
break ;
case "text/xml" :
case "application/xml" :
case "application/json" :
default :
//m_log.Info("[Debug BASE HTTP SERVER]: in default handler");
// Point of note.. the DoWeHaveA methods check for an EXACT path
// if (request.RawUrl.Contains("/CAPS/EQG"))
// {
// int i = 1;
// }
//m_log.Info("[Debug BASE HTTP SERVER]: Checking for LLSD Handler");
if ( DoWeHaveALLSDHandler ( request . RawUrl ) )
{
2012-06-14 22:46:09 +00:00
if ( DebugLevel > = 3 )
2012-09-11 20:48:02 +00:00
LogIncomingToContentTypeHandler ( request ) ;
2012-06-12 23:03:44 +00:00
buffer = HandleLLSDRequests ( request , response ) ;
}
// m_log.DebugFormat("[BASE HTTP SERVER]: Checking for HTTP Handler for request {0}", request.RawUrl);
else if ( DoWeHaveAHTTPHandler ( request . RawUrl ) )
{
2012-06-14 22:46:09 +00:00
if ( DebugLevel > = 3 )
2012-09-11 20:48:02 +00:00
LogIncomingToContentTypeHandler ( request ) ;
2012-06-12 23:03:44 +00:00
buffer = HandleHTTPRequest ( request , response ) ;
}
else
{
2012-06-14 22:46:09 +00:00
if ( DebugLevel > = 3 )
2012-09-11 20:48:02 +00:00
LogIncomingToXmlRpcHandler ( request ) ;
2012-06-12 23:03:44 +00:00
// generic login request.
buffer = HandleXmlRpcRequests ( request , response ) ;
}
break ;
}
}
2011-11-29 16:15:52 +00:00
2012-06-12 23:03:44 +00:00
request . InputStream . Close ( ) ;
2011-11-29 16:15:52 +00:00
2012-06-12 23:03:44 +00:00
if ( buffer ! = null )
{
if ( ! response . SendChunked )
response . ContentLength64 = buffer . LongLength ;
2009-05-04 20:19:21 +00:00
2012-06-12 23:03:44 +00:00
response . OutputStream . Write ( buffer , 0 , buffer . Length ) ;
2009-05-04 20:19:21 +00:00
}
2012-06-12 23:03:44 +00:00
// Do not include the time taken to actually send the response to the caller in the measurement
// time. This is to avoid logging when it's the client that is slow to process rather than the
// server
requestEndTick = Environment . TickCount ;
response . Send ( ) ;
//response.OutputStream.Close();
//response.FreeContext();
2009-05-04 20:19:21 +00:00
}
catch ( SocketException e )
{
// At least on linux, it appears that if the client makes a request without requiring the response,
// an unconnected socket exception is thrown when we close the response output stream. There's no
// obvious way to tell if the client didn't require the response, so instead we'll catch and ignore
// the exception instead.
/ /
// An alternative may be to turn off all response write exceptions on the HttpListener, but let's go
// with the minimum first
2012-04-23 12:27:04 +00:00
m_log . Warn ( String . Format ( "[BASE HTTP SERVER]: HandleRequest threw {0}.\nNOTE: this may be spurious on Linux " , e . Message ) , e ) ;
2009-05-04 20:19:21 +00:00
}
2009-08-05 20:47:48 +00:00
catch ( IOException e )
2009-05-04 20:19:21 +00:00
{
2012-09-22 21:01:07 +00:00
m_log . Error ( String . Format ( "[BASE HTTP SERVER]: HandleRequest() threw {0} " , e . StackTrace ) , e ) ;
2009-05-04 20:19:21 +00:00
}
2011-03-14 11:56:50 +00:00
catch ( Exception e )
2009-05-04 20:19:21 +00:00
{
2012-09-22 21:01:07 +00:00
m_log . Error ( String . Format ( "[BASE HTTP SERVER]: HandleRequest() threw {0} " , e . StackTrace ) , e ) ;
2009-05-04 20:19:21 +00:00
SendHTML500 ( response ) ;
}
2011-01-05 22:32:00 +00:00
finally
{
// Every month or so this will wrap and give bad numbers, not really a problem
2012-06-12 23:03:44 +00:00
// since its just for reporting
int tickdiff = requestEndTick - requestStartTick ;
2012-10-17 23:39:43 +00:00
if ( tickdiff > 3000 & & requestHandler ! = null & & requestHandler . Name ! = "GetTexture" )
2012-05-03 00:45:49 +00:00
{
2011-01-19 01:13:10 +00:00
m_log . InfoFormat (
2012-09-20 23:09:17 +00:00
"[BASE HTTP SERVER]: Slow handling of {0} {1} {2} {3} {4} from {5} took {6}ms" ,
RequestNumber ,
2012-05-03 00:45:49 +00:00
requestMethod ,
uriString ,
requestHandler ! = null ? requestHandler . Name : "" ,
requestHandler ! = null ? requestHandler . Description : "" ,
2012-09-20 22:18:19 +00:00
request . RemoteIPEndPoint ,
tickdiff ) ;
}
else if ( DebugLevel > = 4 )
{
m_log . DebugFormat (
2012-09-20 23:09:17 +00:00
"[BASE HTTP SERVER]: HTTP IN {0} :{1} took {2}ms" ,
RequestNumber ,
Port ,
2012-05-03 00:45:49 +00:00
tickdiff ) ;
}
2011-01-05 22:32:00 +00:00
}
2009-05-04 20:19:21 +00:00
}
2012-09-11 20:48:02 +00:00
private void LogIncomingToStreamHandler ( OSHttpRequest request , IRequestHandler requestHandler )
{
m_log . DebugFormat (
2012-09-20 23:09:17 +00:00
"[BASE HTTP SERVER]: HTTP IN {0} :{1} stream handler {2} {3} {4} {5} from {6}" ,
RequestNumber ,
Port ,
request . HttpMethod ,
request . Url . PathAndQuery ,
requestHandler . Name ,
requestHandler . Description ,
request . RemoteIPEndPoint ) ;
2012-09-11 20:48:02 +00:00
2012-09-20 22:18:19 +00:00
if ( DebugLevel > = 5 )
2012-09-11 20:48:02 +00:00
LogIncomingInDetail ( request ) ;
}
private void LogIncomingToContentTypeHandler ( OSHttpRequest request )
{
m_log . DebugFormat (
2012-09-20 23:09:17 +00:00
"[BASE HTTP SERVER]: HTTP IN {0} :{1} {2} content type handler {3} {4} from {5}" ,
RequestNumber ,
Port ,
2012-10-22 23:44:47 +00:00
( request . ContentType = = null | | request . ContentType = = "" ) ? "not set" : request . ContentType ,
2012-09-20 23:09:17 +00:00
request . HttpMethod ,
request . Url . PathAndQuery ,
request . RemoteIPEndPoint ) ;
2012-09-11 20:48:02 +00:00
2012-09-20 22:18:19 +00:00
if ( DebugLevel > = 5 )
2012-09-11 20:48:02 +00:00
LogIncomingInDetail ( request ) ;
}
private void LogIncomingToXmlRpcHandler ( OSHttpRequest request )
{
m_log . DebugFormat (
2012-09-20 23:09:17 +00:00
"[BASE HTTP SERVER]: HTTP IN {0} :{1} assumed generic XMLRPC request {2} {3} from {4}" ,
RequestNumber ,
Port ,
request . HttpMethod ,
request . Url . PathAndQuery ,
request . RemoteIPEndPoint ) ;
2012-09-11 20:48:02 +00:00
2012-09-20 22:18:19 +00:00
if ( DebugLevel > = 5 )
2012-09-11 20:48:02 +00:00
LogIncomingInDetail ( request ) ;
}
private void LogIncomingInDetail ( OSHttpRequest request )
{
using ( StreamReader reader = new StreamReader ( Util . Copy ( request . InputStream ) , Encoding . UTF8 ) )
{
string output ;
2012-09-20 22:18:19 +00:00
if ( DebugLevel = = 5 )
2012-09-11 20:48:02 +00:00
{
const int sampleLength = 80 ;
2012-11-20 04:10:03 +00:00
char [ ] sampleChars = new char [ sampleLength + 3 ] ;
2012-09-11 20:48:02 +00:00
reader . Read ( sampleChars , 0 , sampleLength ) ;
2012-11-20 04:10:03 +00:00
sampleChars [ 80 ] = '.' ;
sampleChars [ 81 ] = '.' ;
sampleChars [ 82 ] = '.' ;
2012-09-29 01:38:21 +00:00
output = new string ( sampleChars ) ;
2012-09-11 20:48:02 +00:00
}
else
{
2012-09-29 01:38:21 +00:00
output = reader . ReadToEnd ( ) ;
2012-09-11 20:48:02 +00:00
}
2012-11-20 04:10:03 +00:00
m_log . DebugFormat ( "[BASE HTTP SERVER]: {0}" , output . Replace ( "\n" , @"\n" ) ) ;
2012-09-11 20:48:02 +00:00
}
}
2009-05-04 20:19:21 +00:00
private bool TryGetStreamHandler ( string handlerKey , out IRequestHandler streamHandler )
{
string bestMatch = null ;
lock ( m_streamHandlers )
{
foreach ( string pattern in m_streamHandlers . Keys )
{
if ( handlerKey . StartsWith ( pattern ) )
{
if ( String . IsNullOrEmpty ( bestMatch ) | | pattern . Length > bestMatch . Length )
{
bestMatch = pattern ;
}
}
}
2010-09-12 17:43:49 +00:00
2009-05-04 20:19:21 +00:00
if ( String . IsNullOrEmpty ( bestMatch ) )
{
streamHandler = null ;
return false ;
}
else
{
streamHandler = m_streamHandlers [ bestMatch ] ;
return true ;
}
}
}
2009-07-29 02:15:45 +00:00
private bool TryGetPollServiceHTTPHandler ( string handlerKey , out PollServiceEventArgs oServiceEventArgs )
{
string bestMatch = null ;
lock ( m_pollHandlers )
{
foreach ( string pattern in m_pollHandlers . Keys )
{
if ( handlerKey . StartsWith ( pattern ) )
{
if ( String . IsNullOrEmpty ( bestMatch ) | | pattern . Length > bestMatch . Length )
{
bestMatch = pattern ;
}
}
}
if ( String . IsNullOrEmpty ( bestMatch ) )
{
oServiceEventArgs = null ;
return false ;
}
else
{
oServiceEventArgs = m_pollHandlers [ bestMatch ] ;
return true ;
}
}
}
2009-05-04 20:19:21 +00:00
private bool TryGetHTTPHandler ( string handlerKey , out GenericHTTPMethod HTTPHandler )
{
2010-03-16 22:58:12 +00:00
// m_log.DebugFormat("[BASE HTTP HANDLER]: Looking for HTTP handler for {0}", handlerKey);
2010-09-12 17:43:49 +00:00
2009-05-04 20:19:21 +00:00
string bestMatch = null ;
lock ( m_HTTPHandlers )
{
foreach ( string pattern in m_HTTPHandlers . Keys )
{
if ( handlerKey . StartsWith ( pattern ) )
{
if ( String . IsNullOrEmpty ( bestMatch ) | | pattern . Length > bestMatch . Length )
{
bestMatch = pattern ;
}
}
}
if ( String . IsNullOrEmpty ( bestMatch ) )
{
HTTPHandler = null ;
return false ;
}
else
{
HTTPHandler = m_HTTPHandlers [ bestMatch ] ;
return true ;
}
}
}
2012-09-20 23:29:13 +00:00
// private bool TryGetAgentHandler(OSHttpRequest request, OSHttpResponse response, out IHttpAgentHandler agentHandler)
// {
// agentHandler = null;
//
// lock (m_agentHandlers)
// {
// foreach (IHttpAgentHandler handler in m_agentHandlers.Values)
// {
// if (handler.Match(request, response))
// {
// agentHandler = handler;
// return true;
// }
// }
// }
/ /
// return false;
// }
2009-05-04 20:19:21 +00:00
/// <summary>
/// Try all the registered xmlrpc handlers when an xmlrpc request is received.
/// Sends back an XMLRPC unknown request response if no handler is registered for the requested method.
/// </summary>
/// <param name="request"></param>
/// <param name="response"></param>
2012-06-12 23:03:44 +00:00
private byte [ ] HandleXmlRpcRequests ( OSHttpRequest request , OSHttpResponse response )
2009-05-04 20:19:21 +00:00
{
Stream requestStream = request . InputStream ;
Encoding encoding = Encoding . UTF8 ;
StreamReader reader = new StreamReader ( requestStream , encoding ) ;
string requestBody = reader . ReadToEnd ( ) ;
reader . Close ( ) ;
requestStream . Close ( ) ;
2009-06-18 20:01:37 +00:00
//m_log.Debug(requestBody);
requestBody = requestBody . Replace ( "<base64></base64>" , "" ) ;
2012-06-14 03:29:15 +00:00
string responseString = String . Empty ;
2009-05-04 20:19:21 +00:00
XmlRpcRequest xmlRprcRequest = null ;
try
{
xmlRprcRequest = ( XmlRpcRequest ) ( new XmlRpcRequestDeserializer ( ) ) . Deserialize ( requestBody ) ;
}
2012-06-14 22:46:09 +00:00
catch ( XmlException e )
2009-05-04 20:19:21 +00:00
{
2012-06-14 22:46:09 +00:00
if ( DebugLevel > = 1 )
{
if ( DebugLevel > = 2 )
m_log . Warn (
string . Format (
"[BASE HTTP SERVER]: Got XMLRPC request with invalid XML from {0}. XML was '{1}'. Sending blank response. Exception " ,
request . RemoteIPEndPoint , requestBody ) ,
e ) ;
else
{
m_log . WarnFormat (
"[BASE HTTP SERVER]: Got XMLRPC request with invalid XML from {0}, length {1}. Sending blank response." ,
request . RemoteIPEndPoint , requestBody . Length ) ;
}
}
2009-05-04 20:19:21 +00:00
}
if ( xmlRprcRequest ! = null )
{
string methodName = xmlRprcRequest . MethodName ;
if ( methodName ! = null )
{
xmlRprcRequest . Params . Add ( request . RemoteIPEndPoint ) ; // Param[1]
XmlRpcResponse xmlRpcResponse ;
2010-09-12 17:43:49 +00:00
2009-05-04 20:19:21 +00:00
XmlRpcMethod method ;
bool methodWasFound ;
2011-08-22 01:25:58 +00:00
bool keepAlive = false ;
2009-05-04 20:19:21 +00:00
lock ( m_rpcHandlers )
{
methodWasFound = m_rpcHandlers . TryGetValue ( methodName , out method ) ;
2011-08-22 01:25:58 +00:00
if ( methodWasFound )
keepAlive = m_rpcHandlersKeepAlive [ methodName ] ;
2009-09-30 16:00:09 +00:00
}
2010-09-12 17:43:49 +00:00
2009-05-04 20:19:21 +00:00
if ( methodWasFound )
{
xmlRprcRequest . Params . Add ( request . Url ) ; // Param[2]
2011-02-16 16:18:49 +00:00
string xff = "X-Forwarded-For" ;
string xfflower = xff . ToLower ( ) ;
foreach ( string s in request . Headers . AllKeys )
{
if ( s ! = null & & s . Equals ( xfflower ) )
{
xff = xfflower ;
break ;
}
}
xmlRprcRequest . Params . Add ( request . Headers . Get ( xff ) ) ; // Param[3]
2009-05-04 20:19:21 +00:00
try
{
2009-05-23 06:05:20 +00:00
xmlRpcResponse = method ( xmlRprcRequest , request . RemoteIPEndPoint ) ;
2009-05-04 20:19:21 +00:00
}
catch ( Exception e )
2009-12-05 18:23:05 +00:00
{
string errorMessage
= String . Format (
"Requested method [{0}] from {1} threw exception: {2} {3}" ,
methodName , request . RemoteIPEndPoint . Address , e . Message , e . StackTrace ) ;
2009-12-03 17:57:29 +00:00
m_log . ErrorFormat ( "[BASE HTTP SERVER]: {0}" , errorMessage ) ;
2009-05-04 20:19:21 +00:00
// if the registered XmlRpc method threw an exception, we pass a fault-code along
xmlRpcResponse = new XmlRpcResponse ( ) ;
2009-12-03 17:57:29 +00:00
2009-05-04 20:19:21 +00:00
// Code probably set in accordance with http://xmlrpc-epi.sourceforge.net/specs/rfc.fault_codes.php
2010-01-03 21:10:45 +00:00
xmlRpcResponse . SetFault ( - 32603 , errorMessage ) ;
2009-05-04 20:19:21 +00:00
}
2009-12-03 17:57:29 +00:00
2009-05-04 20:19:21 +00:00
// if the method wasn't found, we can't determine KeepAlive state anyway, so lets do it only here
2011-08-22 01:25:58 +00:00
response . KeepAlive = keepAlive ;
2009-05-04 20:19:21 +00:00
}
else
{
xmlRpcResponse = new XmlRpcResponse ( ) ;
2010-09-12 17:43:49 +00:00
2009-05-04 20:19:21 +00:00
// Code set in accordance with http://xmlrpc-epi.sourceforge.net/specs/rfc.fault_codes.php
2009-09-24 14:02:55 +00:00
xmlRpcResponse . SetFault (
2010-09-12 17:43:49 +00:00
XmlRpcErrorCodes . SERVER_ERROR_METHOD ,
2009-09-24 14:02:55 +00:00
String . Format ( "Requested method [{0}] not found" , methodName ) ) ;
2009-05-04 20:19:21 +00:00
}
2012-06-12 23:03:44 +00:00
response . ContentType = "text/xml" ;
2009-05-04 20:19:21 +00:00
responseString = XmlRpcResponseSerializer . Singleton . Serialize ( xmlRpcResponse ) ;
}
else
{
//HandleLLSDRequests(request, response);
response . ContentType = "text/plain" ;
response . StatusCode = 404 ;
response . StatusDescription = "Not Found" ;
response . ProtocolVersion = "HTTP/1.0" ;
2012-06-12 23:03:44 +00:00
responseString = "Not found" ;
2009-05-04 20:19:21 +00:00
response . KeepAlive = false ;
2011-11-29 20:37:03 +00:00
m_log . ErrorFormat (
"[BASE HTTP SERVER]: Handler not found for http request {0} {1}" ,
request . HttpMethod , request . Url . PathAndQuery ) ;
2009-05-04 20:19:21 +00:00
}
}
byte [ ] buffer = Encoding . UTF8 . GetBytes ( responseString ) ;
response . SendChunked = false ;
response . ContentLength64 = buffer . Length ;
response . ContentEncoding = Encoding . UTF8 ;
2012-06-12 23:03:44 +00:00
return buffer ;
2009-05-04 20:19:21 +00:00
}
2012-06-12 23:03:44 +00:00
private byte [ ] HandleLLSDRequests ( OSHttpRequest request , OSHttpResponse response )
2009-05-04 20:19:21 +00:00
{
//m_log.Warn("[BASE HTTP SERVER]: We've figured out it's a LLSD Request");
Stream requestStream = request . InputStream ;
Encoding encoding = Encoding . UTF8 ;
StreamReader reader = new StreamReader ( requestStream , encoding ) ;
string requestBody = reader . ReadToEnd ( ) ;
reader . Close ( ) ;
requestStream . Close ( ) ;
//m_log.DebugFormat("[OGP]: {0}:{1}", request.RawUrl, requestBody);
response . KeepAlive = true ;
OSD llsdRequest = null ;
OSD llsdResponse = null ;
2010-09-12 17:43:49 +00:00
2009-05-04 20:19:21 +00:00
bool LegacyLLSDLoginLibOMV = ( requestBody . Contains ( "passwd" ) & & requestBody . Contains ( "mac" ) & & requestBody . Contains ( "viewer_digest" ) ) ;
2010-09-12 17:43:49 +00:00
2009-05-04 20:19:21 +00:00
if ( requestBody . Length = = 0 )
// Get Request
{
2010-09-12 17:43:49 +00:00
requestBody = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><llsd><map><key>request</key><string>get</string></map></llsd>" ;
2009-05-04 20:19:21 +00:00
}
try
{
2009-08-05 20:47:48 +00:00
llsdRequest = OSDParser . Deserialize ( requestBody ) ;
2009-05-04 20:19:21 +00:00
}
catch ( Exception ex )
{
2009-12-15 16:23:57 +00:00
m_log . Warn ( "[BASE HTTP SERVER]: Error - " + ex . Message ) ;
2009-05-04 20:19:21 +00:00
}
if ( llsdRequest ! = null ) // && m_defaultLlsdHandler != null)
{
LLSDMethod llsdhandler = null ;
if ( TryGetLLSDHandler ( request . RawUrl , out llsdhandler ) & & ! LegacyLLSDLoginLibOMV )
{
// we found a registered llsd handler to service this request
llsdResponse = llsdhandler ( request . RawUrl , llsdRequest , request . RemoteIPEndPoint . ToString ( ) ) ;
}
else
{
// we didn't find a registered llsd handler to service this request
// check if we have a default llsd handler
if ( m_defaultLlsdHandler ! = null )
{
// LibOMV path
2009-05-23 06:14:02 +00:00
llsdResponse = m_defaultLlsdHandler ( llsdRequest , request . RemoteIPEndPoint ) ;
2009-05-04 20:19:21 +00:00
}
else
{
// Oops, no handler for this.. give em the failed message
llsdResponse = GenerateNoLLSDHandlerResponse ( ) ;
}
}
}
else
{
llsdResponse = GenerateNoLLSDHandlerResponse ( ) ;
}
2011-11-29 16:15:52 +00:00
2009-05-04 20:19:21 +00:00
byte [ ] buffer = new byte [ 0 ] ;
2011-11-29 16:15:52 +00:00
2009-05-04 20:19:21 +00:00
if ( llsdResponse . ToString ( ) = = "shutdown404!" )
{
response . ContentType = "text/plain" ;
response . StatusCode = 404 ;
response . StatusDescription = "Not Found" ;
response . ProtocolVersion = "HTTP/1.0" ;
buffer = Encoding . UTF8 . GetBytes ( "Not found" ) ;
}
else
{
2009-08-05 20:47:48 +00:00
// Select an appropriate response format
buffer = BuildLLSDResponse ( request , response , llsdResponse ) ;
2009-05-04 20:19:21 +00:00
}
2009-08-05 20:47:48 +00:00
2009-05-04 20:19:21 +00:00
response . SendChunked = false ;
response . ContentLength64 = buffer . Length ;
response . ContentEncoding = Encoding . UTF8 ;
response . KeepAlive = true ;
2012-06-12 23:03:44 +00:00
return buffer ;
2009-05-04 20:19:21 +00:00
}
2009-08-05 20:47:48 +00:00
private byte [ ] BuildLLSDResponse ( OSHttpRequest request , OSHttpResponse response , OSD llsdResponse )
{
if ( request . AcceptTypes ! = null & & request . AcceptTypes . Length > 0 )
{
foreach ( string strAccept in request . AcceptTypes )
{
switch ( strAccept )
{
case "application/llsd+xml" :
case "application/xml" :
case "text/xml" :
response . ContentType = strAccept ;
return OSDParser . SerializeLLSDXmlBytes ( llsdResponse ) ;
case "application/llsd+json" :
case "application/json" :
response . ContentType = strAccept ;
return Encoding . UTF8 . GetBytes ( OSDParser . SerializeJsonString ( llsdResponse ) ) ;
}
}
}
if ( ! String . IsNullOrEmpty ( request . ContentType ) )
{
switch ( request . ContentType )
{
case "application/llsd+xml" :
case "application/xml" :
case "text/xml" :
response . ContentType = request . ContentType ;
return OSDParser . SerializeLLSDXmlBytes ( llsdResponse ) ;
case "application/llsd+json" :
case "application/json" :
response . ContentType = request . ContentType ;
return Encoding . UTF8 . GetBytes ( OSDParser . SerializeJsonString ( llsdResponse ) ) ;
}
}
2009-08-12 12:49:59 +00:00
// response.ContentType = "application/llsd+json";
2009-10-03 01:31:08 +00:00
// return Util.UTF8.GetBytes(OSDParser.SerializeJsonString(llsdResponse));
2009-08-12 12:49:59 +00:00
response . ContentType = "application/llsd+xml" ;
return OSDParser . SerializeLLSDXmlBytes ( llsdResponse ) ;
2009-08-05 20:47:48 +00:00
}
2009-05-04 20:19:21 +00:00
/// <summary>
/// Checks if we have an Exact path in the LLSD handlers for the path provided
/// </summary>
/// <param name="path">URI of the request</param>
/// <returns>true if we have one, false if not</returns>
private bool DoWeHaveALLSDHandler ( string path )
{
string [ ] pathbase = path . Split ( '/' ) ;
string searchquery = "/" ;
if ( pathbase . Length < 1 )
return false ;
for ( int i = 1 ; i < pathbase . Length ; i + + )
{
searchquery + = pathbase [ i ] ;
if ( pathbase . Length - 1 ! = i )
searchquery + = "/" ;
}
string bestMatch = null ;
2011-08-22 00:52:08 +00:00
lock ( m_llsdHandlers )
2009-05-04 20:19:21 +00:00
{
2011-08-22 00:52:08 +00:00
foreach ( string pattern in m_llsdHandlers . Keys )
2009-05-04 20:19:21 +00:00
{
2011-08-22 00:52:08 +00:00
if ( searchquery . StartsWith ( pattern ) & & searchquery . Length > = pattern . Length )
2009-05-04 20:19:21 +00:00
bestMatch = pattern ;
}
}
// extra kicker to remove the default XMLRPC login case.. just in case..
if ( path ! = "/" & & bestMatch = = "/" & & searchquery ! = "/" )
return false ;
if ( path = = "/" )
return false ;
if ( String . IsNullOrEmpty ( bestMatch ) )
{
return false ;
}
else
{
return true ;
}
}
/// <summary>
/// Checks if we have an Exact path in the HTTP handlers for the path provided
/// </summary>
/// <param name="path">URI of the request</param>
/// <returns>true if we have one, false if not</returns>
private bool DoWeHaveAHTTPHandler ( string path )
{
string [ ] pathbase = path . Split ( '/' ) ;
string searchquery = "/" ;
if ( pathbase . Length < 1 )
return false ;
for ( int i = 1 ; i < pathbase . Length ; i + + )
{
searchquery + = pathbase [ i ] ;
if ( pathbase . Length - 1 ! = i )
searchquery + = "/" ;
}
string bestMatch = null ;
//m_log.DebugFormat("[BASE HTTP HANDLER]: Checking if we have an HTTP handler for {0}", searchquery);
2010-09-12 17:43:49 +00:00
2009-05-04 20:19:21 +00:00
lock ( m_HTTPHandlers )
{
foreach ( string pattern in m_HTTPHandlers . Keys )
{
if ( searchquery . StartsWith ( pattern ) & & searchquery . Length > = pattern . Length )
{
bestMatch = pattern ;
}
}
// extra kicker to remove the default XMLRPC login case.. just in case..
if ( path = = "/" )
return false ;
if ( String . IsNullOrEmpty ( bestMatch ) )
{
return false ;
}
else
{
return true ;
}
}
}
private bool TryGetLLSDHandler ( string path , out LLSDMethod llsdHandler )
{
llsdHandler = null ;
// Pull out the first part of the path
// splitting the path by '/' means we'll get the following return..
// {0}/{1}/{2}
// where {0} isn't something we really control 100%
string [ ] pathbase = path . Split ( '/' ) ;
string searchquery = "/" ;
if ( pathbase . Length < 1 )
return false ;
for ( int i = 1 ; i < pathbase . Length ; i + + )
{
searchquery + = pathbase [ i ] ;
if ( pathbase . Length - 1 ! = i )
searchquery + = "/" ;
}
// while the matching algorithm below doesn't require it, we're expecting a query in the form
/ /
// [] = optional
// /resource/UUID/action[/action]
/ /
// now try to get the closest match to the reigstered path
// at least for OGP, registered path would probably only consist of the /resource/
string bestMatch = null ;
2011-08-22 00:52:08 +00:00
lock ( m_llsdHandlers )
2009-05-04 20:19:21 +00:00
{
2011-08-22 00:52:08 +00:00
foreach ( string pattern in m_llsdHandlers . Keys )
2009-05-04 20:19:21 +00:00
{
2011-08-22 00:52:08 +00:00
if ( searchquery . ToLower ( ) . StartsWith ( pattern . ToLower ( ) ) )
2009-05-04 20:19:21 +00:00
{
2011-08-22 00:52:08 +00:00
if ( String . IsNullOrEmpty ( bestMatch ) | | searchquery . Length > bestMatch . Length )
{
// You have to specifically register for '/' and to get it, you must specificaly request it
/ /
if ( pattern = = "/" & & searchquery = = "/" | | pattern ! = "/" )
bestMatch = pattern ;
}
2009-05-04 20:19:21 +00:00
}
}
2011-08-22 00:52:08 +00:00
if ( String . IsNullOrEmpty ( bestMatch ) )
{
llsdHandler = null ;
return false ;
}
else
{
llsdHandler = m_llsdHandlers [ bestMatch ] ;
return true ;
}
2009-05-04 20:19:21 +00:00
}
}
private OSDMap GenerateNoLLSDHandlerResponse ( )
{
OSDMap map = new OSDMap ( ) ;
map [ "reason" ] = OSD . FromString ( "LLSDRequest" ) ;
map [ "message" ] = OSD . FromString ( "No handler registered for LLSD Requests" ) ;
map [ "login" ] = OSD . FromString ( "false" ) ;
return map ;
}
2012-06-12 23:03:44 +00:00
public byte [ ] HandleHTTPRequest ( OSHttpRequest request , OSHttpResponse response )
2010-09-12 17:43:49 +00:00
{
2010-03-16 22:58:12 +00:00
// m_log.DebugFormat(
2010-09-12 17:43:49 +00:00
// "[BASE HTTP SERVER]: HandleHTTPRequest for request to {0}, method {1}",
2010-03-16 22:58:12 +00:00
// request.RawUrl, request.HttpMethod);
2010-09-12 17:43:49 +00:00
2009-05-04 20:19:21 +00:00
switch ( request . HttpMethod )
{
case "OPTIONS" :
response . StatusCode = ( int ) OSHttpStatusCode . SuccessOk ;
2012-06-12 23:03:44 +00:00
return null ;
2009-05-04 20:19:21 +00:00
default :
2012-06-12 23:03:44 +00:00
return HandleContentVerbs ( request , response ) ;
2009-05-04 20:19:21 +00:00
}
}
2012-06-12 23:03:44 +00:00
private byte [ ] HandleContentVerbs ( OSHttpRequest request , OSHttpResponse response )
2009-05-04 20:19:21 +00:00
{
2010-03-16 22:58:12 +00:00
// m_log.DebugFormat("[BASE HTTP SERVER]: HandleContentVerbs for request to {0}", request.RawUrl);
2010-09-12 17:43:49 +00:00
2009-05-04 20:19:21 +00:00
// This is a test. There's a workable alternative.. as this way sucks.
// We'd like to put this into a text file parhaps that's easily editable.
/ /
// For this test to work, I used the following secondlife.exe parameters
// "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
/ /
// Even after all that, there's still an error, but it's a start.
/ /
// I depend on show_login_form being in the secondlife.exe parameters to figure out
// to display the form, or process it.
// a better way would be nifty.
2012-06-12 23:03:44 +00:00
byte [ ] buffer ;
2009-05-04 20:19:21 +00:00
Stream requestStream = request . InputStream ;
Encoding encoding = Encoding . UTF8 ;
StreamReader reader = new StreamReader ( requestStream , encoding ) ;
string requestBody = reader . ReadToEnd ( ) ;
// avoid warning for now
reader . ReadToEnd ( ) ;
reader . Close ( ) ;
requestStream . Close ( ) ;
Hashtable keysvals = new Hashtable ( ) ;
Hashtable headervals = new Hashtable ( ) ;
Hashtable requestVars = new Hashtable ( ) ;
string host = String . Empty ;
string [ ] querystringkeys = request . QueryString . AllKeys ;
string [ ] rHeaders = request . Headers . AllKeys ;
keysvals . Add ( "body" , requestBody ) ;
keysvals . Add ( "uri" , request . RawUrl ) ;
keysvals . Add ( "content-type" , request . ContentType ) ;
keysvals . Add ( "http-method" , request . HttpMethod ) ;
foreach ( string queryname in querystringkeys )
{
2010-03-16 22:58:12 +00:00
// m_log.DebugFormat(
// "[BASE HTTP SERVER]: Got query paremeter {0}={1}", queryname, request.QueryString[queryname]);
2009-05-04 20:19:21 +00:00
keysvals . Add ( queryname , request . QueryString [ queryname ] ) ;
requestVars . Add ( queryname , keysvals [ queryname ] ) ;
}
foreach ( string headername in rHeaders )
{
2010-03-16 22:58:12 +00:00
// m_log.Debug("[BASE HTTP SERVER]: " + headername + "=" + request.Headers[headername]);
2009-05-04 20:19:21 +00:00
headervals [ headername ] = request . Headers [ headername ] ;
}
if ( headervals . Contains ( "Host" ) )
{
host = ( string ) headervals [ "Host" ] ;
}
2010-03-16 22:58:12 +00:00
keysvals . Add ( "headers" , headervals ) ;
2009-05-04 20:19:21 +00:00
keysvals . Add ( "querystringkeys" , querystringkeys ) ;
keysvals . Add ( "requestvars" , requestVars ) ;
2010-03-16 22:58:12 +00:00
// keysvals.Add("form", request.Form);
2009-05-04 20:19:21 +00:00
if ( keysvals . Contains ( "method" ) )
{
2010-03-16 22:58:12 +00:00
// m_log.Debug("[BASE HTTP SERVER]: Contains Method");
2009-05-04 20:19:21 +00:00
string method = ( string ) keysvals [ "method" ] ;
2010-03-16 22:58:12 +00:00
// m_log.Debug("[BASE HTTP SERVER]: " + requestBody);
2009-05-04 20:19:21 +00:00
GenericHTTPMethod requestprocessor ;
bool foundHandler = TryGetHTTPHandler ( method , out requestprocessor ) ;
if ( foundHandler )
{
Hashtable responsedata1 = requestprocessor ( keysvals ) ;
2012-06-12 23:03:44 +00:00
buffer = DoHTTPGruntWork ( responsedata1 , response ) ;
2009-05-04 20:19:21 +00:00
//SendHTML500(response);
}
else
{
2010-03-16 22:58:12 +00:00
// m_log.Warn("[BASE HTTP SERVER]: Handler Not Found");
2012-06-12 23:03:44 +00:00
buffer = SendHTML404 ( response , host ) ;
2009-05-04 20:19:21 +00:00
}
}
else
{
GenericHTTPMethod requestprocessor ;
bool foundHandler = TryGetHTTPHandlerPathBased ( request . RawUrl , out requestprocessor ) ;
if ( foundHandler )
{
Hashtable responsedata2 = requestprocessor ( keysvals ) ;
2012-06-12 23:03:44 +00:00
buffer = DoHTTPGruntWork ( responsedata2 , response ) ;
2009-05-04 20:19:21 +00:00
//SendHTML500(response);
}
else
{
2010-03-16 22:58:12 +00:00
// m_log.Warn("[BASE HTTP SERVER]: Handler Not Found2");
2012-06-12 23:03:44 +00:00
buffer = SendHTML404 ( response , host ) ;
2009-05-04 20:19:21 +00:00
}
}
2012-06-12 23:03:44 +00:00
return buffer ;
2009-05-04 20:19:21 +00:00
}
private bool TryGetHTTPHandlerPathBased ( string path , out GenericHTTPMethod httpHandler )
{
httpHandler = null ;
// Pull out the first part of the path
// splitting the path by '/' means we'll get the following return..
// {0}/{1}/{2}
// where {0} isn't something we really control 100%
string [ ] pathbase = path . Split ( '/' ) ;
string searchquery = "/" ;
if ( pathbase . Length < 1 )
return false ;
for ( int i = 1 ; i < pathbase . Length ; i + + )
{
searchquery + = pathbase [ i ] ;
if ( pathbase . Length - 1 ! = i )
searchquery + = "/" ;
}
// while the matching algorithm below doesn't require it, we're expecting a query in the form
/ /
// [] = optional
// /resource/UUID/action[/action]
/ /
// now try to get the closest match to the reigstered path
// at least for OGP, registered path would probably only consist of the /resource/
string bestMatch = null ;
// m_log.DebugFormat(
// "[BASE HTTP HANDLER]: TryGetHTTPHandlerPathBased() looking for HTTP handler to match {0}", searchquery);
2010-09-12 17:43:49 +00:00
2009-05-04 20:19:21 +00:00
lock ( m_HTTPHandlers )
{
foreach ( string pattern in m_HTTPHandlers . Keys )
{
if ( searchquery . ToLower ( ) . StartsWith ( pattern . ToLower ( ) ) )
{
if ( String . IsNullOrEmpty ( bestMatch ) | | searchquery . Length > bestMatch . Length )
{
2010-03-16 22:58:12 +00:00
// You have to specifically register for '/' and to get it, you must specifically request it
2009-05-04 20:19:21 +00:00
if ( pattern = = "/" & & searchquery = = "/" | | pattern ! = "/" )
bestMatch = pattern ;
}
}
2009-09-30 16:00:09 +00:00
}
2009-05-04 20:19:21 +00:00
if ( String . IsNullOrEmpty ( bestMatch ) )
{
httpHandler = null ;
return false ;
}
else
{
if ( bestMatch = = "/" & & searchquery ! = "/" )
return false ;
httpHandler = m_HTTPHandlers [ bestMatch ] ;
return true ;
}
}
}
2012-06-12 23:03:44 +00:00
internal byte [ ] DoHTTPGruntWork ( Hashtable responsedata , OSHttpResponse response )
2009-05-04 20:19:21 +00:00
{
//m_log.Info("[BASE HTTP SERVER]: Doing HTTP Grunt work with response");
int responsecode = ( int ) responsedata [ "int_response_code" ] ;
string responseString = ( string ) responsedata [ "str_response_string" ] ;
string contentType = ( string ) responsedata [ "content_type" ] ;
if ( responsedata . ContainsKey ( "error_status_text" ) )
{
response . StatusDescription = ( string ) responsedata [ "error_status_text" ] ;
}
if ( responsedata . ContainsKey ( "http_protocol_version" ) )
{
response . ProtocolVersion = ( string ) responsedata [ "http_protocol_version" ] ;
}
if ( responsedata . ContainsKey ( "keepalive" ) )
{
bool keepalive = ( bool ) responsedata [ "keepalive" ] ;
response . KeepAlive = keepalive ;
}
2009-07-30 18:16:00 +00:00
if ( responsedata . ContainsKey ( "reusecontext" ) )
response . ReuseContext = ( bool ) responsedata [ "reusecontext" ] ;
2010-11-01 12:36:30 +00:00
// Cross-Origin Resource Sharing with simple requests
if ( responsedata . ContainsKey ( "access_control_allow_origin" ) )
response . AddHeader ( "Access-Control-Allow-Origin" , ( string ) responsedata [ "access_control_allow_origin" ] ) ;
2009-05-04 20:19:21 +00:00
//Even though only one other part of the entire code uses HTTPHandlers, we shouldn't expect this
//and should check for NullReferenceExceptions
2010-09-12 17:43:49 +00:00
2009-05-04 20:19:21 +00:00
if ( string . IsNullOrEmpty ( contentType ) )
{
contentType = "text/html" ;
}
// The client ignores anything but 200 here for web login, so ensure that this is 200 for that
response . StatusCode = responsecode ;
if ( responsecode = = ( int ) OSHttpStatusCode . RedirectMovedPermanently )
{
response . RedirectLocation = ( string ) responsedata [ "str_redirect_location" ] ;
response . StatusCode = responsecode ;
}
response . AddHeader ( "Content-Type" , contentType ) ;
byte [ ] buffer ;
2010-09-12 17:43:49 +00:00
if ( ! ( contentType . Contains ( "image" )
| | contentType . Contains ( "x-shockwave-flash" )
2010-10-14 06:19:42 +00:00
| | contentType . Contains ( "application/x-oar" )
| | contentType . Contains ( "application/vnd.ll.mesh" ) ) )
2009-05-04 20:19:21 +00:00
{
// Text
buffer = Encoding . UTF8 . GetBytes ( responseString ) ;
}
else
{
// Binary!
buffer = Convert . FromBase64String ( responseString ) ;
}
response . SendChunked = false ;
response . ContentLength64 = buffer . Length ;
response . ContentEncoding = Encoding . UTF8 ;
2012-06-12 23:03:44 +00:00
return buffer ;
2009-05-04 20:19:21 +00:00
}
2012-06-12 23:03:44 +00:00
public byte [ ] SendHTML404 ( OSHttpResponse response , string host )
2009-05-04 20:19:21 +00:00
{
// I know this statuscode is dumb, but the client doesn't respond to 404s and 500s
response . StatusCode = 404 ;
response . AddHeader ( "Content-type" , "text/html" ) ;
string responseString = GetHTTP404 ( host ) ;
byte [ ] buffer = Encoding . UTF8 . GetBytes ( responseString ) ;
response . SendChunked = false ;
response . ContentLength64 = buffer . Length ;
response . ContentEncoding = Encoding . UTF8 ;
2012-06-12 23:03:44 +00:00
return buffer ;
2009-05-04 20:19:21 +00:00
}
2012-06-12 23:03:44 +00:00
public byte [ ] SendHTML500 ( OSHttpResponse response )
2009-05-04 20:19:21 +00:00
{
// I know this statuscode is dumb, but the client doesn't respond to 404s and 500s
response . StatusCode = ( int ) OSHttpStatusCode . SuccessOk ;
response . AddHeader ( "Content-type" , "text/html" ) ;
string responseString = GetHTTP500 ( ) ;
byte [ ] buffer = Encoding . UTF8 . GetBytes ( responseString ) ;
response . SendChunked = false ;
response . ContentLength64 = buffer . Length ;
response . ContentEncoding = Encoding . UTF8 ;
2012-06-12 23:03:44 +00:00
return buffer ;
2009-05-04 20:19:21 +00:00
}
public void Start ( )
{
StartHTTP ( ) ;
}
private void StartHTTP ( )
{
2012-06-15 01:51:52 +00:00
m_log . InfoFormat (
"[BASE HTTP SERVER]: Starting {0} server on port {1}" , UseSSL ? "HTTPS" : "HTTP" , Port ) ;
2009-05-04 20:19:21 +00:00
try
{
//m_httpListener = new HttpListener();
2011-05-01 18:44:09 +00:00
2009-05-04 20:19:21 +00:00
NotSocketErrors = 0 ;
if ( ! m_ssl )
{
//m_httpListener.Prefixes.Add("http://+:" + m_port + "/");
//m_httpListener.Prefixes.Add("http://10.1.1.5:" + m_port + "/");
2009-07-21 06:47:29 +00:00
m_httpListener2 = CoolHTTPListener . Create ( m_listenIPAddress , ( int ) m_port ) ;
2009-05-04 20:19:21 +00:00
m_httpListener2 . ExceptionThrown + = httpServerException ;
m_httpListener2 . LogWriter = httpserverlog ;
2010-09-12 17:43:49 +00:00
// Uncomment this line in addition to those in HttpServerLogWriter
2009-05-04 20:19:21 +00:00
// if you want more detailed trace information from the HttpServer
//m_httpListener2.UseTraceLogs = true;
2010-09-12 17:43:49 +00:00
2009-09-30 16:00:09 +00:00
//m_httpListener2.DisconnectHandler = httpServerDisconnectMonitor;
2009-05-04 20:19:21 +00:00
}
else
{
//m_httpListener.Prefixes.Add("https://+:" + (m_sslport) + "/");
//m_httpListener.Prefixes.Add("http://+:" + m_port + "/");
2011-05-01 18:44:09 +00:00
m_httpListener2 = CoolHTTPListener . Create ( IPAddress . Any , ( int ) m_port , m_cert ) ;
m_httpListener2 . ExceptionThrown + = httpServerException ;
m_httpListener2 . LogWriter = httpserverlog ;
2009-05-04 20:19:21 +00:00
}
2009-07-21 06:47:29 +00:00
m_httpListener2 . RequestReceived + = OnRequest ;
2009-05-04 20:19:21 +00:00
//m_httpListener.Start();
m_httpListener2 . Start ( 64 ) ;
2009-07-29 02:15:45 +00:00
// Long Poll Service Manager with 3 worker threads a 25 second timeout for no events
m_PollServiceManager = new PollServiceRequestManager ( this , 3 , 25000 ) ;
2009-05-04 20:19:21 +00:00
HTTPDRunning = true ;
//HttpListenerContext context;
//while (true)
//{
// context = m_httpListener.GetContext();
2009-10-19 23:52:27 +00:00
// ThreadPool.UnsafeQueueUserWorkItem(new WaitCallback(HandleRequest), context);
2009-05-04 20:19:21 +00:00
// }
}
catch ( Exception e )
{
2009-12-15 16:23:57 +00:00
m_log . Error ( "[BASE HTTP SERVER]: Error - " + e . Message ) ;
m_log . Error ( "[BASE HTTP SERVER]: Tip: Do you have permission to listen on port " + m_port + ", " + m_sslport + "?" ) ;
2010-09-12 17:43:49 +00:00
// We want this exception to halt the entire server since in current configurations we aren't too
2009-05-04 20:19:21 +00:00
// useful without inbound HTTP.
throw e ;
}
}
public void httpServerDisconnectMonitor ( IHttpClientContext source , SocketError err )
2009-09-30 16:00:09 +00:00
{
2009-05-04 20:19:21 +00:00
switch ( err )
{
case SocketError . NotSocket :
NotSocketErrors + + ;
2010-09-12 17:43:49 +00:00
2009-05-04 20:19:21 +00:00
break ;
}
}
public void httpServerException ( object source , Exception exception )
2009-09-30 16:00:09 +00:00
{
2012-04-23 12:27:04 +00:00
m_log . Error ( String . Format ( "[BASE HTTP SERVER]: {0} had an exception: {1} " , source . ToString ( ) , exception . Message ) , exception ) ;
2009-05-04 20:19:21 +00:00
/ *
if ( HTTPDRunning ) // && NotSocketErrors > 5)
{
Stop ( ) ;
Thread . Sleep ( 200 ) ;
StartHTTP ( ) ;
m_log . Warn ( "[HTTPSERVER]: Died. Trying to kick....." ) ;
}
* /
}
public void Stop ( )
{
HTTPDRunning = false ;
2009-08-27 01:05:46 +00:00
try
{
m_httpListener2 . ExceptionThrown - = httpServerException ;
//m_httpListener2.DisconnectHandler = null;
2009-05-04 20:19:21 +00:00
2009-08-27 01:05:46 +00:00
m_httpListener2 . LogWriter = null ;
m_httpListener2 . RequestReceived - = OnRequest ;
m_httpListener2 . Stop ( ) ;
2010-09-12 17:43:49 +00:00
}
2009-08-27 01:05:46 +00:00
catch ( NullReferenceException )
{
2009-12-15 16:23:57 +00:00
m_log . Warn ( "[BASE HTTP SERVER]: Null Reference when stopping HttpServer." ) ;
2009-08-27 01:05:46 +00:00
}
2009-05-04 20:19:21 +00:00
}
public void RemoveStreamHandler ( string httpMethod , string path )
{
string handlerKey = GetHandlerKey ( httpMethod , path ) ;
//m_log.DebugFormat("[BASE HTTP SERVER]: Removing handler key {0}", handlerKey);
2011-08-22 00:58:50 +00:00
lock ( m_streamHandlers )
m_streamHandlers . Remove ( handlerKey ) ;
2009-05-04 20:19:21 +00:00
}
public void RemoveHTTPHandler ( string httpMethod , string path )
{
lock ( m_HTTPHandlers )
{
if ( httpMethod ! = null & & httpMethod . Length = = 0 )
{
m_HTTPHandlers . Remove ( path ) ;
return ;
}
2010-09-12 17:43:49 +00:00
2009-05-04 20:19:21 +00:00
m_HTTPHandlers . Remove ( GetHandlerKey ( httpMethod , path ) ) ;
}
}
2009-07-29 02:15:45 +00:00
public void RemovePollServiceHTTPHandler ( string httpMethod , string path )
{
lock ( m_pollHandlers )
2011-10-24 22:26:41 +00:00
m_pollHandlers . Remove ( path ) ;
2009-07-29 02:15:45 +00:00
}
2012-09-20 23:29:13 +00:00
// public bool RemoveAgentHandler(string agent, IHttpAgentHandler handler)
// {
// lock (m_agentHandlers)
// {
// IHttpAgentHandler foundHandler;
/ /
// if (m_agentHandlers.TryGetValue(agent, out foundHandler) && foundHandler == handler)
// {
// m_agentHandlers.Remove(agent);
// return true;
// }
// }
/ /
// return false;
// }
2009-05-22 11:37:14 +00:00
public void RemoveXmlRPCHandler ( string method )
{
lock ( m_rpcHandlers )
2011-10-24 22:26:41 +00:00
m_rpcHandlers . Remove ( method ) ;
2009-05-22 11:37:14 +00:00
}
2009-05-04 20:19:21 +00:00
public bool RemoveLLSDHandler ( string path , LLSDMethod handler )
{
2011-08-22 00:58:19 +00:00
lock ( m_llsdHandlers )
2009-05-04 20:19:21 +00:00
{
2011-08-22 00:58:19 +00:00
LLSDMethod foundHandler ;
if ( m_llsdHandlers . TryGetValue ( path , out foundHandler ) & & foundHandler = = handler )
2009-05-04 20:19:21 +00:00
{
2011-08-22 00:58:19 +00:00
m_llsdHandlers . Remove ( path ) ;
return true ;
2009-05-04 20:19:21 +00:00
}
}
return false ;
}
public string GetHTTP404 ( string host )
{
string file = Path . Combine ( "." , "http_404.html" ) ;
if ( ! File . Exists ( file ) )
return getDefaultHTTP404 ( host ) ;
StreamReader sr = File . OpenText ( file ) ;
string result = sr . ReadToEnd ( ) ;
sr . Close ( ) ;
return result ;
}
public string GetHTTP500 ( )
{
string file = Path . Combine ( "." , "http_500.html" ) ;
if ( ! File . Exists ( file ) )
return getDefaultHTTP500 ( ) ;
StreamReader sr = File . OpenText ( file ) ;
string result = sr . ReadToEnd ( ) ;
sr . Close ( ) ;
return result ;
}
// Fallback HTTP responses in case the HTTP error response files don't exist
private static string getDefaultHTTP404 ( string host )
{
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: "-loginpage http://" + host + "/?method=login -loginuri http://" + host + "/" in your link </P></BODY></HTML>" ;
}
private static string getDefaultHTTP500 ( )
{
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>" ;
}
}
public class HttpServerContextObj
{
public IHttpClientContext context = null ;
public IHttpRequest req = null ;
public OSHttpRequest oreq = null ;
public OSHttpResponse oresp = null ;
public HttpServerContextObj ( IHttpClientContext contxt , IHttpRequest reqs )
{
context = contxt ;
req = reqs ;
}
public HttpServerContextObj ( OSHttpRequest osreq , OSHttpResponse osresp )
{
oreq = osreq ;
oresp = osresp ;
}
}
2010-09-12 17:43:49 +00:00
2009-05-04 20:19:21 +00:00
/// <summary>
/// Relays HttpServer log messages to our own logging mechanism.
/// </summary>
2010-03-16 22:58:12 +00:00
/// To use this you must uncomment the switch section
///
/// You may also be able to get additional trace information from HttpServer if you uncomment the UseTraceLogs
/// property in StartHttp() for the HttpListener
2009-05-04 20:19:21 +00:00
public class HttpServerLogWriter : ILogWriter
{
2010-12-10 03:08:31 +00:00
// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
2009-05-04 20:19:21 +00:00
public void Write ( object source , LogPrio priority , string message )
{
/ *
switch ( priority )
{
2010-03-16 22:58:12 +00:00
case LogPrio . Trace :
m_log . DebugFormat ( "[{0}]: {1}" , source , message ) ;
2010-09-12 17:43:49 +00:00
break ;
2010-03-16 22:58:12 +00:00
case LogPrio . Debug :
m_log . DebugFormat ( "[{0}]: {1}" , source , message ) ;
2009-05-04 20:19:21 +00:00
break ;
2010-03-16 22:58:12 +00:00
case LogPrio . Error :
m_log . ErrorFormat ( "[{0}]: {1}" , source , message ) ;
2009-05-04 20:19:21 +00:00
break ;
2010-03-16 22:58:12 +00:00
case LogPrio . Info :
m_log . InfoFormat ( "[{0}]: {1}" , source , message ) ;
2009-05-04 20:19:21 +00:00
break ;
2010-03-16 22:58:12 +00:00
case LogPrio . Warning :
m_log . WarnFormat ( "[{0}]: {1}" , source , message ) ;
2009-05-04 20:19:21 +00:00
break ;
2010-03-16 22:58:12 +00:00
case LogPrio . Fatal :
m_log . ErrorFormat ( "[{0}]: FATAL! - {1}" , source , message ) ;
2009-05-04 20:19:21 +00:00
break ;
default :
break ;
}
* /
2010-09-12 17:43:49 +00:00
2009-05-04 20:19:21 +00:00
return ;
}
}
2010-09-12 17:43:49 +00:00
}