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 ;
2016-10-09 00:01:52 +00:00
using HttpListener = System . Net . HttpListener ;
using LogPrio = HttpServer . LogPrio ;
2012-07-25 22:27:00 +00:00
using OpenSim.Framework.Monitoring ;
2013-11-28 21:07:14 +00:00
using System.IO.Compression ;
2016-10-09 00:01:52 +00:00
using System.Security.Cryptography ;
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 ( ) ;
2015-03-02 19:42:57 +00:00
private static Encoding UTF8NoBOM = new System . Text . UTF8Encoding ( false ) ;
2010-09-12 17:43:49 +00:00
2013-02-07 15:26:48 +00:00
/// <summary>
/// This is a pending websocket request before it got an sucessful upgrade response.
/// The consumer must call handler.HandshakeAndUpgrade() to signal to the handler to
/// start the connection and optionally provide an origin authentication method.
/// </summary>
/// <param name="servicepath"></param>
/// <param name="handler"></param>
public delegate void WebSocketRequestDelegate ( string servicepath , WebSocketHttpServerHandler handler ) ;
2013-02-05 23:02:25 +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 ; }
2013-06-18 22:07:18 +00:00
/// <summary>
/// Statistic for holding number of requests processed.
/// </summary>
private Stat m_requestsProcessedStat ;
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 > ( ) ;
2013-01-15 15:04:16 +00:00
protected Dictionary < string , JsonRPCMethod > jsonRpcHandlers = new Dictionary < string , JsonRPCMethod > ( ) ;
2009-05-04 20:19:21 +00:00
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 > ( ) ;
2013-02-05 23:02:25 +00:00
protected Dictionary < string , WebSocketRequestDelegate > m_WebSocketHandlers =
new Dictionary < string , WebSocketRequestDelegate > ( ) ;
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 string m_SSLCommonName = "" ;
2016-10-09 00:01:52 +00:00
protected List < string > m_certNames = new List < string > ( ) ;
protected List < string > m_certIPs = new List < string > ( ) ;
protected string m_certCN = "" ;
2009-05-04 20:19:21 +00:00
2009-05-30 16:13:40 +00:00
protected IPAddress m_listenIPAddress = IPAddress . Any ;
2014-03-17 20:51:35 +00:00
public PollServiceRequestManager PollServiceRequestManager { get ; private set ; }
2009-07-29 02:15:45 +00:00
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 ;
}
2016-10-09 00:01:52 +00:00
private void load_cert ( string CPath , string CPass )
2009-05-04 20:19:21 +00:00
{
2016-10-09 00:01:52 +00:00
try
{
m_cert = new X509Certificate2 ( CPath , CPass ) ;
X509Extension ext = m_cert . Extensions [ "2.5.29.17" ] ;
if ( ext ! = null )
{
AsnEncodedData asndata = new AsnEncodedData ( ext . Oid , ext . RawData ) ;
string datastr = asndata . Format ( true ) ;
string [ ] lines = datastr . Split ( new char [ ] { '\n' , '\r' } ) ;
foreach ( string s in lines )
{
if ( String . IsNullOrEmpty ( s ) )
continue ;
string [ ] parts = s . Split ( new char [ ] { '=' } ) ;
if ( String . IsNullOrEmpty ( parts [ 0 ] ) )
continue ;
string entryName = parts [ 0 ] . Replace ( " " , "" ) ;
if ( entryName = = "DNSName" )
m_certNames . Add ( parts [ 1 ] ) ;
else if ( entryName = = "IPAddress" )
m_certIPs . Add ( parts [ 1 ] ) ;
}
}
m_certCN = m_cert . GetNameInfo ( X509NameType . SimpleName , false ) ;
}
catch
2009-05-04 20:19:21 +00:00
{
2016-10-09 00:01:52 +00:00
throw new Exception ( "SSL cert load error" ) ;
}
}
public BaseHttpServer ( uint port , bool ssl , uint sslport , string CN , string CPath , string CPass )
{
m_port = port ;
if ( ssl )
{
if ( string . IsNullOrEmpty ( CPath ) )
2016-10-06 20:35:11 +00:00
throw new Exception ( "invalid main http server cert path" ) ;
2016-10-09 00:01:52 +00:00
if ( Uri . CheckHostName ( CN ) = = UriHostNameType . Unknown )
throw new Exception ( "invalid main http server CN (ExternalHostName)" ) ;
m_certNames . Clear ( ) ;
m_certIPs . Clear ( ) ;
m_certCN = "" ;
m_ssl = true ;
2009-05-04 20:19:21 +00:00
m_sslport = sslport ;
2016-10-09 00:01:52 +00:00
load_cert ( CPath , CPass ) ;
if ( ! CheckSSLCertHost ( CN ) )
throw new Exception ( "invalid main http server CN (ExternalHostName)" ) ;
m_SSLCommonName = CN ;
if ( m_cert . Issuer = = m_cert . Subject )
m_log . Warn ( "Self signed certificate. Clients need to allow this (some viewers debug option NoVerifySSLcert must be set to true" ) ;
2009-05-04 20:19:21 +00:00
}
2016-10-09 00:01:52 +00:00
else
m_ssl = false ;
2009-05-04 20:19:21 +00:00
}
2016-10-09 19:18:20 +00:00
public BaseHttpServer ( uint port , bool ssl , string CPath , string CPass )
2011-05-01 18:44:09 +00:00
{
2016-10-09 19:18:20 +00:00
m_port = port ;
if ( ssl )
2011-05-01 18:44:09 +00:00
{
2016-10-09 00:01:52 +00:00
load_cert ( CPath , CPass ) ;
if ( m_cert . Issuer = = m_cert . Subject )
m_log . Warn ( "Self signed certificate. Http clients need to allow this" ) ;
2016-10-09 19:18:20 +00:00
m_ssl = true ;
m_sslport = port ;
2011-05-01 18:44:09 +00:00
}
2016-10-09 19:18:20 +00:00
else
m_ssl = false ;
2011-05-01 18:44:09 +00:00
}
2016-10-09 00:01:52 +00:00
static bool MatchDNS ( string hostname , string dns )
{
int indx = dns . IndexOf ( '*' ) ;
if ( indx = = - 1 )
return ( String . Compare ( hostname , dns , true , CultureInfo . InvariantCulture ) = = 0 ) ;
int dnslen = dns . Length ;
dnslen - - ;
if ( indx = = dnslen )
return true ; // just * ?
if ( indx > dnslen - 2 )
return false ; // 2 short ?
if ( dns [ indx + 1 ] ! = '.' )
return false ;
int indx2 = dns . IndexOf ( '*' , indx + 1 ) ;
if ( indx2 ! = - 1 )
return false ; // there can only be one;
string end = dns . Substring ( indx + 1 ) ;
int hostlen = hostname . Length ;
int endlen = end . Length ;
int length = hostlen - endlen ;
if ( length < = 0 )
return false ;
if ( String . Compare ( hostname , length , end , 0 , endlen , true , CultureInfo . InvariantCulture ) ! = 0 )
return false ;
if ( indx = = 0 )
{
indx2 = hostname . IndexOf ( '.' ) ;
return ( ( indx2 = = - 1 ) | | ( indx2 > = length ) ) ;
}
string start = dns . Substring ( 0 , indx ) ;
return ( String . Compare ( hostname , 0 , start , 0 , start . Length , true , CultureInfo . InvariantCulture ) = = 0 ) ;
}
public bool CheckSSLCertHost ( string hostname )
{
UriHostNameType htype = Uri . CheckHostName ( hostname ) ;
if ( htype = = UriHostNameType . Unknown | | htype = = UriHostNameType . Basic )
return false ;
if ( htype = = UriHostNameType . Dns )
{
foreach ( string name in m_certNames )
{
if ( MatchDNS ( hostname , name ) )
return true ;
}
if ( MatchDNS ( hostname , m_certCN ) )
return true ;
}
else
{
foreach ( string ip in m_certIPs )
{
if ( String . Compare ( hostname , ip , true , CultureInfo . InvariantCulture ) ! = 0 )
return true ;
}
}
return false ;
}
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 ) ;
}
}
}
2013-02-05 23:02:25 +00:00
public void AddWebSocketHandler ( string servicepath , WebSocketRequestDelegate handler )
{
lock ( m_WebSocketHandlers )
{
if ( ! m_WebSocketHandlers . ContainsKey ( servicepath ) )
m_WebSocketHandlers . Add ( servicepath , handler ) ;
}
}
public void RemoveWebSocketHandler ( string servicepath )
{
lock ( m_WebSocketHandlers )
if ( m_WebSocketHandlers . ContainsKey ( servicepath ) )
m_WebSocketHandlers . Remove ( servicepath ) ;
}
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
}
2013-01-15 15:04:16 +00:00
// JsonRPC
public bool AddJsonRPCHandler ( string method , JsonRPCMethod handler )
{
lock ( jsonRpcHandlers )
{
jsonRpcHandlers . Add ( method , handler ) ;
}
return true ;
}
public JsonRPCMethod GetJsonRPCHandler ( string method )
{
lock ( jsonRpcHandlers )
{
if ( jsonRpcHandlers . ContainsKey ( method ) )
{
return jsonRpcHandlers [ method ] ;
}
else
{
return null ;
}
}
}
public List < string > GetJsonRpcHandlerKeys ( )
{
lock ( jsonRpcHandlers )
return new List < string > ( jsonRpcHandlers . Keys ) ;
}
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 ;
}
2014-03-17 20:51:35 +00:00
public void OnRequest ( object source , RequestEventArgs args )
2009-07-21 06:47:29 +00:00
{
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
{
2013-07-15 22:22:39 +00:00
psEvArgs . RequestsReceived + + ;
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 ( ) ;
2012-09-26 15:17:49 +00:00
reader . Close ( ) ;
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
2014-03-17 20:51:35 +00:00
PollServiceRequestManager . Enqueue ( psreq ) ;
2009-12-15 16:34:27 +00:00
}
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
}
2013-06-18 22:07:18 +00:00
private void OnHandleRequestIOThread ( IHttpClientContext context , IHttpRequest request )
2009-05-04 20:19:21 +00:00
{
OSHttpRequest req = new OSHttpRequest ( context , request ) ;
2013-02-05 23:02:25 +00:00
WebSocketRequestDelegate dWebSocketRequestDelegate = null ;
lock ( m_WebSocketHandlers )
{
if ( m_WebSocketHandlers . ContainsKey ( req . RawUrl ) )
dWebSocketRequestDelegate = m_WebSocketHandlers [ req . RawUrl ] ;
}
if ( dWebSocketRequestDelegate ! = null )
{
2013-02-07 15:26:48 +00:00
dWebSocketRequestDelegate ( req . Url . AbsolutePath , new WebSocketHttpServerHandler ( req , context , 8192 ) ) ;
2013-02-05 23:02:25 +00:00
return ;
}
2009-07-29 20:32:54 +00:00
OSHttpResponse resp = new OSHttpResponse ( new HttpResponse ( context , request ) , context ) ;
2016-09-03 07:50:22 +00:00
// resp.ReuseContext = true;
2016-08-21 19:52:31 +00:00
// resp.ReuseContext = false;
2013-06-18 22:07:18 +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
{
2013-03-16 07:14:11 +00:00
byte [ ] buffer500 = SendHTML500 ( response ) ;
2014-04-01 12:00:22 +00:00
response . OutputStream . Write ( buffer500 , 0 , buffer500 . Length ) ;
response . Send ( ) ;
2011-03-14 11:56:50 +00:00
}
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
2012-12-05 21:52:10 +00:00
Culture . SetCurrentCulture ( ) ;
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.
2013-02-05 23:02:25 +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 ;
2013-01-15 15:04:16 +00:00
case "application/json-rpc" :
if ( DebugLevel > = 3 )
LogIncomingToContentTypeHandler ( request ) ;
buffer = HandleJsonRpcRequests ( request , response ) ;
break ;
2012-06-12 23:03:44 +00:00
case "text/xml" :
case "application/xml" :
case "application/json" :
2013-01-15 15:04:16 +00:00
2012-06-12 23:03:44 +00:00
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 )
{
2013-11-28 21:07:14 +00:00
if ( WebUtil . DebugLevel > = 5 )
{
string output = System . Text . Encoding . UTF8 . GetString ( buffer ) ;
if ( WebUtil . DebugLevel > = 6 )
{
// Always truncate binary blobs. We don't have a ContentType, so detect them using the request name.
if ( ( requestHandler ! = null & & requestHandler . Name = = "GetMesh" ) )
{
if ( output . Length > WebUtil . MaxRequestDiagLength )
output = output . Substring ( 0 , WebUtil . MaxRequestDiagLength ) + "..." ;
}
}
2014-04-29 06:58:03 +00:00
WebUtil . LogResponseDetail ( RequestNumber , output ) ;
2013-11-28 21:07:14 +00:00
}
2013-07-08 21:12:11 +00:00
if ( ! response . SendChunked & & response . ContentLength64 < = 0 )
2012-06-12 23:03:44 +00:00
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
{
2013-12-19 08:51:57 +00:00
m_log . Error ( "[BASE HTTP SERVER]: HandleRequest() threw exception " , 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
{
2013-12-19 08:51:57 +00:00
m_log . Error ( "[BASE HTTP SERVER]: HandleRequest() threw exception " , e ) ;
2013-03-16 07:14:11 +00:00
try
{
byte [ ] buffer500 = SendHTML500 ( response ) ;
2014-04-01 12:00:22 +00:00
response . OutputStream . Write ( buffer500 , 0 , buffer500 . Length ) ;
response . Send ( ) ;
2013-03-16 07:14:11 +00:00
}
catch
{
}
2009-05-04 20:19:21 +00:00
}
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-09-16 14:42:30 +00:00
if ( tickdiff > 3000 & & ( requestHandler = = null | | requestHandler . Name = = null | | requestHandler . Name ! = "GetTexture" ) )
2012-05-03 00:45:49 +00:00
{
2011-01-19 01:13:10 +00:00
m_log . InfoFormat (
2013-11-28 21:07:14 +00:00
"[LOGHTTP] Slow handling of {0} {1} {2} {3} {4} from {5} took {6}ms" ,
2012-09-20 23:09:17 +00:00
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 (
2013-11-28 21:07:14 +00:00
"[LOGHTTP] HTTP IN {0} :{1} took {2}ms" ,
2012-09-20 23:09:17 +00:00
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 (
2013-11-28 21:07:14 +00:00
"[LOGHTTP] HTTP IN {0} :{1} stream handler {2} {3} {4} {5} from {6}" ,
2012-09-20 23:09:17 +00:00
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 (
2013-11-28 21:07:14 +00:00
"[LOGHTTP] HTTP IN {0} :{1} {2} content type handler {3} {4} from {5}" ,
2012-09-20 23:09:17 +00:00
RequestNumber ,
Port ,
2013-11-15 21:45:08 +00:00
string . IsNullOrEmpty ( 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 (
2013-11-28 21:07:14 +00:00
"[LOGHTTP] HTTP IN {0} :{1} assumed generic XMLRPC request {2} {3} from {4}" ,
2012-09-20 23:09:17 +00:00
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 )
{
2013-11-28 21:07:14 +00:00
if ( request . ContentType = = "application/octet-stream" )
return ; // never log these; they're just binary data
Stream inputStream = Util . Copy ( request . InputStream ) ;
2014-06-01 14:39:11 +00:00
Stream innerStream = null ;
try
2012-09-11 20:48:02 +00:00
{
2014-06-01 14:39:11 +00:00
if ( ( request . Headers [ "Content-Encoding" ] = = "gzip" ) | | ( request . Headers [ "X-Content-Encoding" ] = = "gzip" ) )
2012-09-11 20:48:02 +00:00
{
2014-06-01 14:39:11 +00:00
innerStream = inputStream ;
inputStream = new GZipStream ( innerStream , System . IO . Compression . CompressionMode . Decompress ) ;
2012-09-11 20:48:02 +00:00
}
2014-06-01 14:39:11 +00:00
using ( StreamReader reader = new StreamReader ( inputStream , Encoding . UTF8 ) )
2012-09-11 20:48:02 +00:00
{
2014-06-01 14:39:11 +00:00
string output ;
if ( DebugLevel = = 5 )
{
char [ ] chars = new char [ WebUtil . MaxRequestDiagLength + 1 ] ; // +1 so we know to add "..." only if needed
int len = reader . Read ( chars , 0 , WebUtil . MaxRequestDiagLength + 1 ) ;
output = new string ( chars , 0 , Math . Min ( len , WebUtil . MaxRequestDiagLength ) ) ;
if ( len > WebUtil . MaxRequestDiagLength )
output + = "..." ;
}
else
{
output = reader . ReadToEnd ( ) ;
}
2012-09-11 20:48:02 +00:00
2014-06-01 14:39:11 +00:00
m_log . DebugFormat ( "[LOGHTTP] {0}" , Util . BinaryToASCII ( output ) ) ;
}
}
finally
{
if ( innerStream ! = null )
innerStream . Dispose ( ) ;
inputStream . Dispose ( ) ;
2012-09-11 20:48:02 +00:00
}
}
2014-04-02 14:11:32 +00:00
private readonly string HANDLER_SEPARATORS = "/?&#-" ;
2014-04-02 05:52:44 +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 )
{
2014-04-02 05:52:44 +00:00
if ( ( handlerKey = = pattern )
| | ( handlerKey . StartsWith ( pattern ) & & ( HANDLER_SEPARATORS . IndexOf ( handlerKey [ pattern . Length ] ) > = 0 ) ) )
2009-05-04 20:19:21 +00:00
{
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 )
{
2014-04-02 05:52:44 +00:00
if ( ( handlerKey = = pattern )
| | ( handlerKey . StartsWith ( pattern ) & & ( HANDLER_SEPARATORS . IndexOf ( handlerKey [ pattern . Length ] ) > = 0 ) ) )
2009-07-29 02:15:45 +00:00
{
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 )
{
2014-04-02 05:52:44 +00:00
if ( ( handlerKey = = pattern )
| | ( handlerKey . StartsWith ( pattern ) & & ( HANDLER_SEPARATORS . IndexOf ( handlerKey [ pattern . Length ] ) > = 0 ) ) )
2009-05-04 20:19:21 +00:00
{
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
{
2014-06-01 14:39:11 +00:00
String requestBody ;
2009-05-04 20:19:21 +00:00
2014-06-01 14:39:11 +00:00
Stream requestStream = request . InputStream ;
Stream innerStream = null ;
try
{
if ( ( request . Headers [ "Content-Encoding" ] = = "gzip" ) | | ( request . Headers [ "X-Content-Encoding" ] = = "gzip" ) )
{
innerStream = requestStream ;
requestStream = new GZipStream ( innerStream , System . IO . Compression . CompressionMode . Decompress ) ;
}
2014-03-25 17:09:03 +00:00
2014-06-01 14:39:11 +00:00
using ( StreamReader reader = new StreamReader ( requestStream , Encoding . UTF8 ) )
{
requestBody = reader . ReadToEnd ( ) ;
}
}
finally
{
if ( innerStream ! = null )
innerStream . Dispose ( ) ;
requestStream . Dispose ( ) ;
}
2009-05-04 20:19:21 +00:00
2009-06-18 20:01:37 +00:00
//m_log.Debug(requestBody);
requestBody = requestBody . Replace ( "<base64></base64>" , "" ) ;
2014-06-01 14:39:11 +00:00
2012-06-14 03:29:15 +00:00
string responseString = String . Empty ;
2009-05-04 20:19:21 +00:00
XmlRpcRequest xmlRprcRequest = null ;
2014-10-24 01:12:30 +00:00
bool gridproxy = false ;
if ( requestBody . Contains ( "encoding=\"utf-8" ) )
{
int channelindx = - 1 ;
int optionsindx = requestBody . IndexOf ( ">options<" ) ;
if ( optionsindx > 0 )
{
channelindx = requestBody . IndexOf ( ">channel<" ) ;
if ( optionsindx < channelindx )
gridproxy = true ;
}
}
2009-05-04 20:19:21 +00:00
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]
2014-10-24 01:12:30 +00:00
if ( gridproxy )
xmlRprcRequest . Params . Add ( "gridproxy" ) ; // Param[4]
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" ;
2013-08-04 17:20:10 +00:00
using ( MemoryStream outs = new MemoryStream ( ) )
2015-03-02 19:42:57 +00:00
using ( XmlTextWriter writer = new XmlTextWriter ( outs , UTF8NoBOM ) )
2013-08-04 17:20:10 +00:00
{
2014-06-01 14:39:11 +00:00
writer . Formatting = Formatting . None ;
XmlRpcResponseSerializer . Singleton . Serialize ( writer , xmlRpcResponse ) ;
writer . Flush ( ) ;
outs . Flush ( ) ;
outs . Position = 0 ;
using ( StreamReader sr = new StreamReader ( outs ) )
2013-08-04 17:20:10 +00:00
{
2014-06-01 14:39:11 +00:00
responseString = sr . ReadToEnd ( ) ;
2013-08-04 17:20:10 +00:00
}
}
2009-05-04 20:19:21 +00:00
}
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
}
2013-01-23 13:14:21 +00:00
// JsonRpc (v2.0 only)
// Batch requests not yet supported
2013-01-15 15:04:16 +00:00
private byte [ ] HandleJsonRpcRequests ( OSHttpRequest request , OSHttpResponse response )
{
Stream requestStream = request . InputStream ;
JsonRpcResponse jsonRpcResponse = new JsonRpcResponse ( ) ;
OSDMap jsonRpcRequest = null ;
try
{
jsonRpcRequest = ( OSDMap ) OSDParser . DeserializeJson ( requestStream ) ;
}
catch ( LitJson . JsonException e )
{
jsonRpcResponse . Error . Code = ErrorCode . InternalError ;
jsonRpcResponse . Error . Message = e . Message ;
}
requestStream . Close ( ) ;
if ( jsonRpcRequest ! = null )
{
if ( jsonRpcRequest . ContainsKey ( "jsonrpc" ) | | jsonRpcRequest [ "jsonrpc" ] . AsString ( ) = = "2.0" )
{
jsonRpcResponse . JsonRpc = "2.0" ;
// If we have no id, then it's a "notification"
if ( jsonRpcRequest . ContainsKey ( "id" ) )
{
jsonRpcResponse . Id = jsonRpcRequest [ "id" ] . AsString ( ) ;
}
string methodname = jsonRpcRequest [ "method" ] ;
JsonRPCMethod method ;
if ( jsonRpcHandlers . ContainsKey ( methodname ) )
{
lock ( jsonRpcHandlers )
{
jsonRpcHandlers . TryGetValue ( methodname , out method ) ;
}
2013-01-23 13:14:21 +00:00
bool res = false ;
try
{
res = method ( jsonRpcRequest , ref jsonRpcResponse ) ;
if ( ! res )
{
// The handler sent back an unspecified error
if ( jsonRpcResponse . Error . Code = = 0 )
{
jsonRpcResponse . Error . Code = ErrorCode . InternalError ;
}
}
}
catch ( Exception e )
{
string ErrorMessage = string . Format ( "[BASE HTTP SERVER]: Json-Rpc Handler Error method {0} - {1}" , methodname , e . Message ) ;
m_log . Error ( ErrorMessage ) ;
jsonRpcResponse . Error . Code = ErrorCode . InternalError ;
jsonRpcResponse . Error . Message = ErrorMessage ;
}
2013-01-15 15:04:16 +00:00
}
else // Error no hanlder defined for requested method
{
jsonRpcResponse . Error . Code = ErrorCode . InvalidRequest ;
jsonRpcResponse . Error . Message = string . Format ( "No handler defined for {0}" , methodname ) ;
}
}
else // not json-rpc 2.0 could be v1
{
jsonRpcResponse . Error . Code = ErrorCode . InvalidRequest ;
jsonRpcResponse . Error . Message = "Must be valid json-rpc 2.0 see: http://www.jsonrpc.org/specification" ;
if ( jsonRpcRequest . ContainsKey ( "id" ) )
jsonRpcResponse . Id = jsonRpcRequest [ "id" ] . AsString ( ) ;
}
}
response . KeepAlive = true ;
string responseData = string . Empty ;
responseData = jsonRpcResponse . Serialize ( ) ;
byte [ ] buffer = Encoding . UTF8 . GetBytes ( responseData ) ;
return buffer ;
}
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);
2016-06-14 15:58:37 +00:00
response . KeepAlive = true ;
2009-05-04 20:19:21 +00:00
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
{
2011-05-18 02:12:37 +00:00
int responsecode ;
2012-09-14 19:24:25 +00:00
string responseString = String . Empty ;
byte [ ] responseData = null ;
2011-05-18 02:12:37 +00:00
string contentType ;
2009-05-04 20:19:21 +00:00
2011-05-18 02:12:37 +00:00
if ( responsedata = = null )
{
responsecode = 500 ;
responseString = "No response could be obtained" ;
contentType = "text/plain" ;
responsedata = new Hashtable ( ) ;
}
else
{
2011-05-26 10:42:01 +00:00
try
{
//m_log.Info("[BASE HTTP SERVER]: Doing HTTP Grunt work with response");
responsecode = ( int ) responsedata [ "int_response_code" ] ;
2012-09-14 19:24:25 +00:00
if ( responsedata [ "bin_response_data" ] ! = null )
responseData = ( byte [ ] ) responsedata [ "bin_response_data" ] ;
else
responseString = ( string ) responsedata [ "str_response_string" ] ;
2011-05-26 10:42:01 +00:00
contentType = ( string ) responsedata [ "content_type" ] ;
2012-09-14 21:09:07 +00:00
if ( responseString = = null )
responseString = String . Empty ;
2011-05-26 10:42:01 +00:00
}
catch
{
responsecode = 500 ;
responseString = "No response could be obtained" ;
contentType = "text/plain" ;
responsedata = new Hashtable ( ) ;
}
2011-05-18 02:12:37 +00:00
}
2009-05-04 20:19:21 +00:00
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" ] ;
}
2015-09-23 22:59:50 +00:00
/ *
2009-05-04 20:19:21 +00:00
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" ] ;
2015-09-23 22:59:50 +00:00
* /
// disable this things
response . KeepAlive = false ;
2016-09-03 07:50:22 +00:00
// response.ReuseContext = false;
2009-07-30 18:16:00 +00:00
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" ;
}
2015-09-23 22:59:50 +00:00
2009-05-04 20:19:21 +00:00
// The client ignores anything but 200 here for web login, so ensure that this is 200 for that
2015-09-23 22:59:50 +00:00
2009-05-04 20:19:21 +00:00
response . StatusCode = responsecode ;
if ( responsecode = = ( int ) OSHttpStatusCode . RedirectMovedPermanently )
{
response . RedirectLocation = ( string ) responsedata [ "str_redirect_location" ] ;
response . StatusCode = responsecode ;
}
response . AddHeader ( "Content-Type" , contentType ) ;
2012-09-14 19:24:25 +00:00
if ( responsedata . ContainsKey ( "headers" ) )
{
Hashtable headerdata = ( Hashtable ) responsedata [ "headers" ] ;
foreach ( string header in headerdata . Keys )
response . AddHeader ( header , ( string ) headerdata [ header ] ) ;
}
2009-05-04 20:19:21 +00:00
byte [ ] buffer ;
2012-09-14 19:24:25 +00:00
if ( responseData ! = null )
2009-05-04 20:19:21 +00:00
{
2012-09-14 19:24:25 +00:00
buffer = responseData ;
2009-05-04 20:19:21 +00:00
}
else
{
2012-09-14 19:24:25 +00:00
if ( ! ( contentType . Contains ( "image" )
| | contentType . Contains ( "x-shockwave-flash" )
| | contentType . Contains ( "application/x-oar" )
| | contentType . Contains ( "application/vnd.ll.mesh" ) ) )
{
// Text
buffer = Encoding . UTF8 . GetBytes ( responseString ) ;
}
else
{
// Binary!
buffer = Convert . FromBase64String ( responseString ) ;
}
2009-05-04 20:19:21 +00:00
2012-09-14 19:24:25 +00:00
response . SendChunked = false ;
response . ContentLength64 = buffer . Length ;
response . ContentEncoding = Encoding . UTF8 ;
}
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
}
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 ;
2013-03-16 07:14:11 +00:00
2012-06-12 23:03:44 +00:00
return buffer ;
2009-05-04 20:19:21 +00:00
}
public void Start ( )
{
2016-10-09 19:18:20 +00:00
Start ( true , true ) ;
2009-05-04 20:19:21 +00:00
}
2014-03-17 20:51:35 +00:00
/// <summary>
/// Start the http server
/// </summary>
/// <param name='processPollRequestsAsync'>
/// If true then poll responses are performed asynchronsly.
/// Option exists to allow regression tests to perform processing synchronously.
/// </param>
2016-10-09 19:18:20 +00:00
public void Start ( bool performPollResponsesAsync , bool runPool )
2009-05-04 20:19:21 +00:00
{
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
2016-10-09 19:18:20 +00:00
if ( runPool )
{
PollServiceRequestManager = new PollServiceRequestManager ( this , performPollResponsesAsync , 2 , 25000 ) ;
PollServiceRequestManager . Start ( ) ;
}
2014-03-17 20:51:35 +00:00
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 ;
}
2013-06-18 22:07:18 +00:00
m_requestsProcessedStat
= new Stat (
2013-06-19 19:48:12 +00:00
"HTTPRequestsServed" ,
2013-06-18 22:07:18 +00:00
"Number of inbound HTTP requests processed" ,
"" ,
"requests" ,
"httpserver" ,
Port . ToString ( ) ,
StatType . Pull ,
MeasuresOfInterest . AverageChangeOverTime ,
stat = > stat . Value = RequestNumber ,
StatVerbosity . Debug ) ;
StatsManager . RegisterStat ( m_requestsProcessedStat ) ;
2009-05-04 20:19:21 +00:00
}
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-07-15 10:28:58 +00:00
if ( source . ToString ( ) = = "HttpServer.HttpListener" & & exception . ToString ( ) . StartsWith ( "Mono.Security.Protocol.Tls.TlsException" ) )
return ;
2009-12-15 16:23:57 +00:00
m_log . ErrorFormat ( "[BASE HTTP SERVER]: {0} had an exception {1}" , source . ToString ( ) , exception . ToString ( ) ) ;
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 ;
2013-06-18 22:07:18 +00:00
StatsManager . DeregisterStat ( m_requestsProcessedStat ) ;
2009-08-27 01:05:46 +00:00
try
{
2014-03-17 20:51:35 +00:00
PollServiceRequestManager . Stop ( ) ;
2013-01-19 02:04:36 +00:00
2009-08-27 01:05:46 +00:00
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 )
{
2013-10-05 22:36:58 +00:00
if ( path = = null ) return ; // Caps module isn't loaded, tries to remove handler where path = null
2009-05-04 20:19:21 +00:00
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 ) ;
2013-03-03 14:40:44 +00:00
}
public void RemoveJsonRPCHandler ( string method )
{
lock ( jsonRpcHandlers )
jsonRpcHandlers . 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
}