2010-03-10 04:15:36 +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 .
* * Neither the name of the OpenSimulator Project nor the
* 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 ;
2010-12-09 02:53:15 +00:00
using System.Collections ;
2010-03-03 22:38:00 +00:00
using System.Collections.Generic ;
using System.Collections.Specialized ;
2011-02-12 19:02:42 +00:00
using System.Globalization ;
2010-03-03 22:38:00 +00:00
using System.IO ;
2011-05-08 19:20:00 +00:00
using System.IO.Compression ;
2010-03-03 22:38:00 +00:00
using System.Net ;
using System.Net.Security ;
using System.Reflection ;
using System.Text ;
using System.Web ;
2011-04-13 03:24:28 +00:00
using System.Xml ;
using System.Xml.Serialization ;
2014-04-24 11:21:05 +00:00
using System.Xml.Linq ;
2010-03-03 22:38:00 +00:00
using log4net ;
2014-04-24 11:21:05 +00:00
using Nwc.XmlRpc ;
2010-03-03 22:38:00 +00:00
using OpenMetaverse.StructuredData ;
2014-03-27 15:46:37 +00:00
using XMLResponseHelper = OpenSim . Framework . SynchronousRestObjectRequester . XMLResponseHelper ;
2010-03-03 22:38:00 +00:00
2014-05-23 23:19:43 +00:00
using OpenSim.Framework.ServiceAuth ;
2010-03-03 22:38:00 +00:00
namespace OpenSim.Framework
{
/// <summary>
/// Miscellaneous static methods and extension methods related to the web
/// </summary>
public static class WebUtil
{
private static readonly ILog m_log =
LogManager . GetLogger (
MethodBase . GetCurrentMethod ( ) . DeclaringType ) ;
2012-09-20 21:36:47 +00:00
/// <summary>
/// Control the printing of certain debug messages.
/// </summary>
/// <remarks>
/// If DebugLevel >= 3 then short notices about outgoing HTTP requests are logged.
/// </remarks>
public static int DebugLevel { get ; set ; }
2012-05-04 00:12:56 +00:00
/// <summary>
/// Request number for diagnostic purposes.
/// </summary>
2014-07-13 16:19:58 +00:00
public static int RequestNumber { get ; set ; }
2011-01-05 22:32:00 +00:00
2013-08-05 22:44:48 +00:00
/// <summary>
/// Control where OSD requests should be serialized per endpoint.
/// </summary>
public static bool SerializeOSDRequestsPerEndpoint { get ; set ; }
2012-05-04 00:12:56 +00:00
/// <summary>
/// this is the header field used to communicate the local request id
/// used for performance and debugging
/// </summary>
2011-01-05 22:32:00 +00:00
public const string OSHeaderRequestID = "opensim-request-id" ;
2012-05-04 00:12:56 +00:00
/// <summary>
/// Number of milliseconds a call can take before it is considered
/// a "long" call for warning & debugging purposes
/// </summary>
2015-09-03 17:39:08 +00:00
public const int LongCallTime = 3000 ;
2011-01-05 22:32:00 +00:00
2012-05-04 00:12:56 +00:00
/// <summary>
/// The maximum length of any data logged because of a long request time.
/// </summary>
/// <remarks>
/// This is to truncate any really large post data, such as an asset. In theory, the first section should
/// give us useful information about the call (which agent it relates to if applicable, etc.).
2013-11-28 21:07:14 +00:00
/// This is also used to truncate messages when using DebugLevel 5.
2012-05-04 00:12:56 +00:00
/// </remarks>
2013-11-28 21:07:14 +00:00
public const int MaxRequestDiagLength = 200 ;
2012-05-04 00:12:56 +00:00
/// <summary>
/// Dictionary of end points
/// </summary>
2012-02-28 04:04:11 +00:00
private static Dictionary < string , object > m_endpointSerializer = new Dictionary < string , object > ( ) ;
private static object EndPointLock ( string url )
{
System . Uri uri = new System . Uri ( url ) ;
string endpoint = string . Format ( "{0}:{1}" , uri . Host , uri . Port ) ;
lock ( m_endpointSerializer )
{
object eplock = null ;
if ( ! m_endpointSerializer . TryGetValue ( endpoint , out eplock ) )
{
eplock = new object ( ) ;
m_endpointSerializer . Add ( endpoint , eplock ) ;
// m_log.WarnFormat("[WEB UTIL] add a new host to end point serializer {0}",endpoint);
}
return eplock ;
}
}
2012-04-25 23:43:31 +00:00
2012-02-27 23:15:03 +00:00
#region JSONRequest
2010-03-03 22:38:00 +00:00
2010-12-30 04:47:51 +00:00
/// <summary>
/// PUT JSON-encoded data to a web service that returns LLSD or
/// JSON data
/// </summary>
2011-05-08 21:23:33 +00:00
public static OSDMap PutToServiceCompressed ( string url , OSDMap data , int timeout )
{
2014-04-24 11:19:03 +00:00
return ServiceOSDRequest ( url , data , "PUT" , timeout , true , false ) ;
2011-05-08 21:23:33 +00:00
}
2011-05-02 16:04:34 +00:00
public static OSDMap PutToService ( string url , OSDMap data , int timeout )
2010-12-30 04:47:51 +00:00
{
2014-04-24 11:19:03 +00:00
return ServiceOSDRequest ( url , data , "PUT" , timeout , false , false ) ;
2010-12-30 04:47:51 +00:00
}
2011-05-02 16:04:34 +00:00
2014-04-24 11:19:03 +00:00
public static OSDMap PostToService ( string url , OSDMap data , int timeout , bool rpc )
2010-12-30 04:47:51 +00:00
{
2014-04-24 11:19:03 +00:00
return ServiceOSDRequest ( url , data , "POST" , timeout , false , rpc ) ;
2011-05-08 19:20:00 +00:00
}
public static OSDMap PostToServiceCompressed ( string url , OSDMap data , int timeout )
{
2014-04-24 11:19:03 +00:00
return ServiceOSDRequest ( url , data , "POST" , timeout , true , false ) ;
2010-12-30 04:47:51 +00:00
}
2011-05-02 16:04:34 +00:00
public static OSDMap GetFromService ( string url , int timeout )
2010-12-30 04:47:51 +00:00
{
2014-04-24 11:19:03 +00:00
return ServiceOSDRequest ( url , null , "GET" , timeout , false , false ) ;
2010-12-30 04:47:51 +00:00
}
2014-04-24 11:19:03 +00:00
public static OSDMap ServiceOSDRequest ( string url , OSDMap data , string method , int timeout , bool compressed , bool rpc )
2012-02-28 04:04:11 +00:00
{
2013-08-05 22:44:48 +00:00
if ( SerializeOSDRequestsPerEndpoint )
{
lock ( EndPointLock ( url ) )
{
2014-04-24 11:19:03 +00:00
return ServiceOSDRequestWorker ( url , data , method , timeout , compressed , rpc ) ;
2013-08-05 22:44:48 +00:00
}
}
else
{
2014-04-24 11:19:03 +00:00
return ServiceOSDRequestWorker ( url , data , method , timeout , compressed , rpc ) ;
2013-08-05 22:44:48 +00:00
}
2012-02-28 04:04:11 +00:00
}
2013-06-12 20:34:20 +00:00
public static void LogOutgoingDetail ( Stream outputStream )
2013-11-28 21:07:14 +00:00
{
LogOutgoingDetail ( "" , outputStream ) ;
}
public static void LogOutgoingDetail ( string context , Stream outputStream )
2013-06-12 20:34:20 +00:00
{
2014-06-01 14:39:11 +00:00
using ( Stream stream = Util . Copy ( outputStream ) )
using ( StreamReader reader = new StreamReader ( stream , Encoding . UTF8 ) )
2013-06-12 20:34:20 +00:00
{
string output ;
if ( DebugLevel = = 5 )
{
2013-11-28 21:07:14 +00:00
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 , len ) ;
2013-06-12 20:34:20 +00:00
}
else
{
output = reader . ReadToEnd ( ) ;
}
2013-11-28 21:07:14 +00:00
LogOutgoingDetail ( context , output ) ;
2013-06-12 20:34:20 +00:00
}
}
2014-04-24 11:21:05 +00:00
public static void LogOutgoingDetail ( string type , int reqnum , string output )
2013-11-28 21:07:14 +00:00
{
2014-04-24 11:21:05 +00:00
LogOutgoingDetail ( string . Format ( "{0} {1}: " , type , reqnum ) , output ) ;
2013-11-28 21:07:14 +00:00
}
public static void LogOutgoingDetail ( string context , string output )
2013-06-12 20:34:20 +00:00
{
if ( DebugLevel = = 5 )
{
2013-11-28 21:07:14 +00:00
if ( output . Length > MaxRequestDiagLength )
output = output . Substring ( 0 , MaxRequestDiagLength ) + "..." ;
2013-06-12 20:34:20 +00:00
}
2013-11-28 21:07:14 +00:00
m_log . DebugFormat ( "[LOGHTTP]: {0}{1}" , context , Util . BinaryToASCII ( output ) ) ;
}
2014-04-24 11:21:05 +00:00
public static void LogResponseDetail ( int reqnum , Stream inputStream )
2013-11-28 21:07:14 +00:00
{
2014-04-24 11:21:05 +00:00
LogOutgoingDetail ( string . Format ( "RESPONSE {0}: " , reqnum ) , inputStream ) ;
2013-11-28 21:07:14 +00:00
}
2014-04-29 06:58:03 +00:00
public static void LogResponseDetail ( int reqnum , string input )
2013-11-28 21:07:14 +00:00
{
2014-04-29 06:58:03 +00:00
LogOutgoingDetail ( string . Format ( "RESPONSE {0}: " , reqnum ) , input ) ;
2013-06-12 20:34:20 +00:00
}
2014-04-24 11:19:03 +00:00
private static OSDMap ServiceOSDRequestWorker ( string url , OSDMap data , string method , int timeout , bool compressed , bool rpc )
2010-12-30 04:47:51 +00:00
{
2012-05-04 00:12:56 +00:00
int reqnum = RequestNumber + + ;
2012-09-20 21:36:47 +00:00
if ( DebugLevel > = 3 )
2014-04-24 11:21:05 +00:00
m_log . DebugFormat ( "[LOGHTTP]: HTTP OUT {0} JSON-RPC {1} to {2}" ,
reqnum , method , url ) ;
2010-12-30 04:47:51 +00:00
string errorMessage = "unknown error" ;
int tickstart = Util . EnvironmentTickCount ( ) ;
2011-01-05 22:32:00 +00:00
int tickdata = 0 ;
2014-08-17 01:12:45 +00:00
int tickcompressdata = 0 ;
int tickJsondata = 0 ;
int compsize = 0 ;
2012-05-04 00:12:56 +00:00
string strBuffer = null ;
2011-01-05 22:32:00 +00:00
2010-12-30 04:47:51 +00:00
try
{
HttpWebRequest request = ( HttpWebRequest ) WebRequest . Create ( url ) ;
request . Method = method ;
request . Timeout = timeout ;
2011-01-05 22:32:00 +00:00
request . KeepAlive = false ;
request . MaximumAutomaticRedirections = 10 ;
2011-05-02 16:04:34 +00:00
request . ReadWriteTimeout = timeout / 4 ;
2011-01-05 22:32:00 +00:00
request . Headers [ OSHeaderRequestID ] = reqnum . ToString ( ) ;
2017-01-05 19:07:37 +00:00
2010-12-30 04:47:51 +00:00
// If there is some input, write it into the request
if ( data ! = null )
{
2013-06-12 20:34:20 +00:00
strBuffer = OSDParser . SerializeJsonString ( data ) ;
2014-08-17 01:12:45 +00:00
tickJsondata = Util . EnvironmentTickCountSubtract ( tickstart ) ;
2013-06-12 20:34:20 +00:00
if ( DebugLevel > = 5 )
2014-04-24 11:21:05 +00:00
LogOutgoingDetail ( "SEND" , reqnum , strBuffer ) ;
2013-06-12 20:34:20 +00:00
2010-12-30 04:47:51 +00:00
byte [ ] buffer = System . Text . Encoding . UTF8 . GetBytes ( strBuffer ) ;
2011-05-01 00:40:21 +00:00
2014-04-24 11:19:03 +00:00
request . ContentType = rpc ? "application/json-rpc" : "application/json" ;
2017-01-05 19:07:37 +00:00
2011-05-08 19:20:00 +00:00
if ( compressed )
{
2014-03-25 17:09:03 +00:00
request . Headers [ "X-Content-Encoding" ] = "gzip" ; // can't set "Content-Encoding" because old OpenSims fail if they get an unrecognized Content-Encoding
2014-03-25 14:20:21 +00:00
2011-05-08 19:20:00 +00:00
using ( MemoryStream ms = new MemoryStream ( ) )
{
2014-06-01 14:39:11 +00:00
using ( GZipStream comp = new GZipStream ( ms , CompressionMode . Compress , true ) )
2011-05-08 19:20:00 +00:00
{
comp . Write ( buffer , 0 , buffer . Length ) ;
2011-05-12 03:44:03 +00:00
// We need to close the gzip stream before we write it anywhere
// because apparently something important related to gzip compression
2014-06-01 14:39:11 +00:00
// gets written on the stream upon Dispose()
2011-05-08 19:20:00 +00:00
}
2011-05-12 03:44:03 +00:00
byte [ ] buf = ms . ToArray ( ) ;
2014-08-17 01:12:45 +00:00
tickcompressdata = Util . EnvironmentTickCountSubtract ( tickstart ) ;
2011-05-12 03:44:03 +00:00
request . ContentLength = buf . Length ; //Count bytes to send
2014-08-17 01:12:45 +00:00
compsize = buf . Length ;
2011-05-12 03:44:03 +00:00
using ( Stream requestStream = request . GetRequestStream ( ) )
requestStream . Write ( buf , 0 , ( int ) buf . Length ) ;
2011-05-08 19:20:00 +00:00
}
}
else
{
2014-08-17 01:12:45 +00:00
compsize = buffer . Length ;
2015-09-02 18:54:53 +00:00
2011-05-08 19:20:00 +00:00
request . ContentLength = buffer . Length ; //Count bytes to send
using ( Stream requestStream = request . GetRequestStream ( ) )
2014-03-25 14:20:21 +00:00
requestStream . Write ( buffer , 0 , buffer . Length ) ; //Send it
2011-05-08 19:20:00 +00:00
}
2010-12-30 04:47:51 +00:00
}
2017-01-05 19:07:37 +00:00
2011-01-05 22:32:00 +00:00
// capture how much time was spent writing, this may seem silly
// but with the number concurrent requests, this often blocks
tickdata = Util . EnvironmentTickCountSubtract ( tickstart ) ;
using ( WebResponse response = request . GetResponse ( ) )
2010-12-30 04:47:51 +00:00
{
2011-01-05 22:32:00 +00:00
using ( Stream responseStream = response . GetResponseStream ( ) )
2010-12-30 04:47:51 +00:00
{
2014-02-27 23:13:26 +00:00
using ( StreamReader reader = new StreamReader ( responseStream ) )
{
string responseStr = reader . ReadToEnd ( ) ;
2013-11-28 21:07:14 +00:00
if ( WebUtil . DebugLevel > = 5 )
2014-04-24 11:21:05 +00:00
WebUtil . LogResponseDetail ( reqnum , responseStr ) ;
2014-02-27 23:13:26 +00:00
return CanonicalizeResults ( responseStr ) ;
}
2010-12-30 04:47:51 +00:00
}
}
}
catch ( WebException we )
{
errorMessage = we . Message ;
if ( we . Status = = WebExceptionStatus . ProtocolError )
{
2013-02-27 00:21:02 +00:00
using ( HttpWebResponse webResponse = ( HttpWebResponse ) we . Response )
errorMessage = String . Format ( "[{0}] {1}" , webResponse . StatusCode , webResponse . StatusDescription ) ;
2010-12-30 04:47:51 +00:00
}
}
catch ( Exception ex )
{
errorMessage = ex . Message ;
2011-07-10 15:27:20 +00:00
m_log . Debug ( "[WEB UTIL]: Exception making request: " + ex . ToString ( ) ) ;
2010-12-30 04:47:51 +00:00
}
finally
{
int tickdiff = Util . EnvironmentTickCountSubtract ( tickstart ) ;
2011-01-05 22:32:00 +00:00
if ( tickdiff > LongCallTime )
2014-04-24 11:21:05 +00:00
{
2012-05-04 00:12:56 +00:00
m_log . InfoFormat (
2014-08-17 01:12:45 +00:00
"[WEB UTIL]: Slow ServiceOSD request {0} {1} {2} took {3}ms, {4}ms writing({5} at Json; {6} at comp), {7} bytes ({8} uncomp): {9}" ,
2012-05-04 00:12:56 +00:00
reqnum ,
method ,
url ,
tickdiff ,
tickdata ,
2014-08-17 01:12:45 +00:00
tickJsondata ,
tickcompressdata ,
compsize ,
strBuffer ! = null ? strBuffer . Length : 0 ,
2015-09-02 18:54:53 +00:00
2012-05-04 00:12:56 +00:00
strBuffer ! = null
? ( strBuffer . Length > MaxRequestDiagLength ? strBuffer . Remove ( MaxRequestDiagLength ) : strBuffer )
: "" ) ;
2014-04-24 11:21:05 +00:00
}
2012-09-20 22:18:19 +00:00
else if ( DebugLevel > = 4 )
2014-04-24 11:21:05 +00:00
{
m_log . DebugFormat ( "[LOGHTTP]: HTTP OUT {0} took {1}ms, {2}ms writing" ,
2012-09-20 22:18:19 +00:00
reqnum , tickdiff , tickdata ) ;
2014-04-24 11:21:05 +00:00
}
2010-12-30 04:47:51 +00:00
}
2017-01-05 19:07:37 +00:00
2012-04-25 23:43:31 +00:00
m_log . DebugFormat (
2014-04-24 11:21:05 +00:00
"[LOGHTTP]: JSON-RPC request {0} {1} to {2} FAILED: {3}" , reqnum , method , url , errorMessage ) ;
2012-04-25 23:43:31 +00:00
2010-12-30 04:47:51 +00:00
return ErrorResponseMap ( errorMessage ) ;
}
/// <summary>
/// Since there are no consistencies in the way web requests are
/// formed, we need to do a little guessing about the result format.
/// Keys:
/// Success|success == the success fail of the request
/// _RawResult == the raw string that came back
/// _Result == the OSD unpacked string
/// </summary>
private static OSDMap CanonicalizeResults ( string response )
{
OSDMap result = new OSDMap ( ) ;
// Default values
result [ "Success" ] = OSD . FromBoolean ( true ) ;
result [ "success" ] = OSD . FromBoolean ( true ) ;
result [ "_RawResult" ] = OSD . FromString ( response ) ;
result [ "_Result" ] = new OSDMap ( ) ;
2017-01-05 19:07:37 +00:00
2010-12-30 04:47:51 +00:00
if ( response . Equals ( "true" , System . StringComparison . OrdinalIgnoreCase ) )
return result ;
if ( response . Equals ( "false" , System . StringComparison . OrdinalIgnoreCase ) )
{
result [ "Success" ] = OSD . FromBoolean ( false ) ;
result [ "success" ] = OSD . FromBoolean ( false ) ;
return result ;
}
2017-01-05 19:07:37 +00:00
try
2010-12-30 04:47:51 +00:00
{
OSD responseOSD = OSDParser . Deserialize ( response ) ;
if ( responseOSD . Type = = OSDType . Map )
{
result [ "_Result" ] = ( OSDMap ) responseOSD ;
return result ;
}
}
2011-11-25 22:19:57 +00:00
catch
2010-12-30 04:47:51 +00:00
{
// don't need to treat this as an error... we're just guessing anyway
2011-11-19 01:16:07 +00:00
// m_log.DebugFormat("[WEB UTIL] couldn't decode <{0}>: {1}",response,e.Message);
2010-12-30 04:47:51 +00:00
}
2017-01-05 19:07:37 +00:00
2010-12-30 04:47:51 +00:00
return result ;
}
2017-01-05 19:07:37 +00:00
2012-02-27 23:15:03 +00:00
#endregion JSONRequest
#region FormRequest
2010-03-03 22:38:00 +00:00
/// <summary>
/// POST URL-encoded form data to a web service that returns LLSD or
/// JSON data
/// </summary>
public static OSDMap PostToService ( string url , NameValueCollection data )
2011-01-05 22:32:00 +00:00
{
2015-09-03 17:39:08 +00:00
return ServiceFormRequest ( url , data , 30000 ) ;
2011-01-05 22:32:00 +00:00
}
2017-01-05 19:07:37 +00:00
2011-01-05 22:32:00 +00:00
public static OSDMap ServiceFormRequest ( string url , NameValueCollection data , int timeout )
2012-02-28 04:04:11 +00:00
{
lock ( EndPointLock ( url ) )
{
return ServiceFormRequestWorker ( url , data , timeout ) ;
}
}
private static OSDMap ServiceFormRequestWorker ( string url , NameValueCollection data , int timeout )
2010-03-03 22:38:00 +00:00
{
2012-05-04 00:12:56 +00:00
int reqnum = RequestNumber + + ;
2011-01-05 22:32:00 +00:00
string method = ( data ! = null & & data [ "RequestMethod" ] ! = null ) ? data [ "RequestMethod" ] : "unknown" ;
2012-09-20 21:36:47 +00:00
if ( DebugLevel > = 3 )
2014-04-24 11:21:05 +00:00
m_log . DebugFormat ( "[LOGHTTP]: HTTP OUT {0} ServiceForm '{1}' to {2}" ,
reqnum , method , url ) ;
2017-01-05 19:07:37 +00:00
2011-01-05 22:32:00 +00:00
string errorMessage = "unknown error" ;
2010-12-30 04:47:51 +00:00
int tickstart = Util . EnvironmentTickCount ( ) ;
2011-01-05 22:32:00 +00:00
int tickdata = 0 ;
2012-05-04 00:12:56 +00:00
string queryString = null ;
2010-03-03 22:38:00 +00:00
try
{
HttpWebRequest request = ( HttpWebRequest ) HttpWebRequest . Create ( url ) ;
request . Method = "POST" ;
2011-01-05 22:32:00 +00:00
request . Timeout = timeout ;
request . KeepAlive = false ;
request . MaximumAutomaticRedirections = 10 ;
request . ReadWriteTimeout = timeout / 4 ;
request . Headers [ OSHeaderRequestID ] = reqnum . ToString ( ) ;
2017-01-05 19:07:37 +00:00
2011-01-05 22:32:00 +00:00
if ( data ! = null )
{
2012-05-04 00:12:56 +00:00
queryString = BuildQueryString ( data ) ;
2013-06-12 20:34:20 +00:00
if ( DebugLevel > = 5 )
2014-04-24 11:21:05 +00:00
LogOutgoingDetail ( "SEND" , reqnum , queryString ) ;
2013-06-12 20:34:20 +00:00
2011-01-05 22:32:00 +00:00
byte [ ] buffer = System . Text . Encoding . UTF8 . GetBytes ( queryString ) ;
2017-01-05 19:07:37 +00:00
2011-01-05 22:32:00 +00:00
request . ContentLength = buffer . Length ;
request . ContentType = "application/x-www-form-urlencoded" ;
using ( Stream requestStream = request . GetRequestStream ( ) )
requestStream . Write ( buffer , 0 , buffer . Length ) ;
}
// capture how much time was spent writing, this may seem silly
// but with the number concurrent requests, this often blocks
tickdata = Util . EnvironmentTickCountSubtract ( tickstart ) ;
2010-03-03 22:38:00 +00:00
using ( WebResponse response = request . GetResponse ( ) )
{
using ( Stream responseStream = response . GetResponseStream ( ) )
{
2014-02-27 23:13:26 +00:00
using ( StreamReader reader = new StreamReader ( responseStream ) )
{
string responseStr = reader . ReadToEnd ( ) ;
2013-11-28 21:07:14 +00:00
if ( WebUtil . DebugLevel > = 5 )
2014-04-24 11:21:05 +00:00
WebUtil . LogResponseDetail ( reqnum , responseStr ) ;
2014-02-27 23:13:26 +00:00
OSD responseOSD = OSDParser . Deserialize ( responseStr ) ;
2010-04-23 01:55:31 +00:00
2014-02-27 23:13:26 +00:00
if ( responseOSD . Type = = OSDType . Map )
return ( OSDMap ) responseOSD ;
}
2010-03-03 22:38:00 +00:00
}
}
}
2010-12-30 04:47:51 +00:00
catch ( WebException we )
{
errorMessage = we . Message ;
if ( we . Status = = WebExceptionStatus . ProtocolError )
{
2013-02-27 00:21:02 +00:00
using ( HttpWebResponse webResponse = ( HttpWebResponse ) we . Response )
errorMessage = String . Format ( "[{0}] {1}" , webResponse . StatusCode , webResponse . StatusDescription ) ;
2010-12-30 04:47:51 +00:00
}
}
2010-03-03 22:38:00 +00:00
catch ( Exception ex )
{
errorMessage = ex . Message ;
}
2010-12-30 04:47:51 +00:00
finally
{
int tickdiff = Util . EnvironmentTickCountSubtract ( tickstart ) ;
2011-01-05 22:32:00 +00:00
if ( tickdiff > LongCallTime )
2014-04-24 11:21:05 +00:00
{
2012-05-04 00:12:56 +00:00
m_log . InfoFormat (
2014-04-24 11:21:05 +00:00
"[LOGHTTP]: Slow ServiceForm request {0} '{1}' to {2} took {3}ms, {4}ms writing, {5}" ,
reqnum , method , url , tickdiff , tickdata ,
2012-05-04 00:12:56 +00:00
queryString ! = null
? ( queryString . Length > MaxRequestDiagLength ) ? queryString . Remove ( MaxRequestDiagLength ) : queryString
: "" ) ;
2014-04-24 11:21:05 +00:00
}
2012-09-20 22:18:19 +00:00
else if ( DebugLevel > = 4 )
2014-04-24 11:21:05 +00:00
{
m_log . DebugFormat ( "[LOGHTTP]: HTTP OUT {0} took {1}ms, {2}ms writing" ,
2012-09-20 22:18:19 +00:00
reqnum , tickdiff , tickdata ) ;
2014-04-24 11:21:05 +00:00
}
2010-12-30 04:47:51 +00:00
}
2010-03-03 22:38:00 +00:00
2014-04-24 11:21:05 +00:00
m_log . WarnFormat ( "[LOGHTTP]: ServiceForm request {0} '{1}' to {2} failed: {3}" , reqnum , method , url , errorMessage ) ;
2012-04-25 23:43:31 +00:00
2010-12-30 04:47:51 +00:00
return ErrorResponseMap ( errorMessage ) ;
2010-03-03 22:38:00 +00:00
}
2010-12-30 04:47:51 +00:00
/// <summary>
/// Create a response map for an error, trying to keep
/// the result formats consistent
/// </summary>
private static OSDMap ErrorResponseMap ( string msg )
{
OSDMap result = new OSDMap ( ) ;
result [ "Success" ] = "False" ;
result [ "Message" ] = OSD . FromString ( "Service request failed: " + msg ) ;
return result ;
}
2012-02-27 23:15:03 +00:00
#endregion FormRequest
2017-01-05 19:07:37 +00:00
2010-03-03 22:38:00 +00:00
#region Uri
/// <summary>
/// Combines a Uri that can contain both a base Uri and relative path
/// with a second relative path fragment
/// </summary>
/// <param name="uri">Starting (base) Uri</param>
/// <param name="fragment">Relative path fragment to append to the end
/// of the Uri</param>
/// <returns>The combined Uri</returns>
/// <remarks>This is similar to the Uri constructor that takes a base
/// Uri and the relative path, except this method can append a relative
/// path fragment on to an existing relative path</remarks>
public static Uri Combine ( this Uri uri , string fragment )
{
string fragment1 = uri . Fragment ;
string fragment2 = fragment ;
if ( ! fragment1 . EndsWith ( "/" ) )
fragment1 = fragment1 + '/' ;
if ( fragment2 . StartsWith ( "/" ) )
fragment2 = fragment2 . Substring ( 1 ) ;
return new Uri ( uri , fragment1 + fragment2 ) ;
}
/// <summary>
/// Combines a Uri that can contain both a base Uri and relative path
/// with a second relative path fragment. If the fragment is absolute,
/// it will be returned without modification
/// </summary>
/// <param name="uri">Starting (base) Uri</param>
/// <param name="fragment">Relative path fragment to append to the end
/// of the Uri, or an absolute Uri to return unmodified</param>
/// <returns>The combined Uri</returns>
public static Uri Combine ( this Uri uri , Uri fragment )
{
if ( fragment . IsAbsoluteUri )
return fragment ;
string fragment1 = uri . Fragment ;
string fragment2 = fragment . ToString ( ) ;
if ( ! fragment1 . EndsWith ( "/" ) )
fragment1 = fragment1 + '/' ;
if ( fragment2 . StartsWith ( "/" ) )
fragment2 = fragment2 . Substring ( 1 ) ;
return new Uri ( uri , fragment1 + fragment2 ) ;
}
/// <summary>
2017-01-05 19:07:37 +00:00
/// Appends a query string to a Uri that may or may not have existing
2010-03-03 22:38:00 +00:00
/// query parameters
/// </summary>
/// <param name="uri">Uri to append the query to</param>
/// <param name="query">Query string to append. Can either start with ?
/// or just containg key/value pairs</param>
/// <returns>String representation of the Uri with the query string
/// appended</returns>
public static string AppendQuery ( this Uri uri , string query )
{
if ( String . IsNullOrEmpty ( query ) )
return uri . ToString ( ) ;
if ( query [ 0 ] = = '?' | | query [ 0 ] = = '&' )
query = query . Substring ( 1 ) ;
string uriStr = uri . ToString ( ) ;
if ( uriStr . Contains ( "?" ) )
return uriStr + '&' + query ;
else
return uriStr + '?' + query ;
}
#endregion Uri
#region NameValueCollection
/// <summary>
/// Convert a NameValueCollection into a query string. This is the
/// inverse of HttpUtility.ParseQueryString()
/// </summary>
/// <param name="parameters">Collection of key/value pairs to convert</param>
/// <returns>A query string with URL-escaped values</returns>
public static string BuildQueryString ( NameValueCollection parameters )
{
List < string > items = new List < string > ( parameters . Count ) ;
foreach ( string key in parameters . Keys )
{
2010-03-26 19:21:05 +00:00
string [ ] values = parameters . GetValues ( key ) ;
if ( values ! = null )
{
foreach ( string value in values )
items . Add ( String . Concat ( key , "=" , HttpUtility . UrlEncode ( value ? ? String . Empty ) ) ) ;
}
2010-03-03 22:38:00 +00:00
}
return String . Join ( "&" , items . ToArray ( ) ) ;
}
/// <summary>
2017-01-05 19:07:37 +00:00
///
2010-03-03 22:38:00 +00:00
/// </summary>
/// <param name="collection"></param>
/// <param name="key"></param>
/// <returns></returns>
public static string GetOne ( this NameValueCollection collection , string key )
{
string [ ] values = collection . GetValues ( key ) ;
if ( values ! = null & & values . Length > 0 )
return values [ 0 ] ;
return null ;
}
#endregion NameValueCollection
#region Stream
/// <summary>
2017-01-05 19:07:37 +00:00
/// Copies the contents of one stream to another, starting at the
2010-03-03 22:38:00 +00:00
/// current position of each stream
/// </summary>
2017-01-05 19:07:37 +00:00
/// <param name="copyFrom">The stream to copy from, at the position
2010-03-03 22:38:00 +00:00
/// where copying should begin</param>
2017-01-05 19:07:37 +00:00
/// <param name="copyTo">The stream to copy to, at the position where
2010-03-03 22:38:00 +00:00
/// bytes should be written</param>
/// <param name="maximumBytesToCopy">The maximum bytes to copy</param>
/// <returns>The total number of bytes copied</returns>
/// <remarks>
/// Copying begins at the streams' current positions. The positions are
/// NOT reset after copying is complete.
2012-03-12 17:07:04 +00:00
/// NOTE!! .NET 4.0 adds the method 'Stream.CopyTo(stream, bufferSize)'.
/// This function could be replaced with that method once we move
/// totally to .NET 4.0. For versions before, this routine exists.
/// This routine used to be named 'CopyTo' but the int parameter has
/// a different meaning so this method was renamed to avoid any confusion.
2010-03-03 22:38:00 +00:00
/// </remarks>
2012-03-12 17:07:04 +00:00
public static int CopyStream ( this Stream copyFrom , Stream copyTo , int maximumBytesToCopy )
2010-03-03 22:38:00 +00:00
{
byte [ ] buffer = new byte [ 4096 ] ;
int readBytes ;
int totalCopiedBytes = 0 ;
while ( ( readBytes = copyFrom . Read ( buffer , 0 , Math . Min ( 4096 , maximumBytesToCopy ) ) ) > 0 )
{
int writeBytes = Math . Min ( maximumBytesToCopy , readBytes ) ;
copyTo . Write ( buffer , 0 , writeBytes ) ;
totalCopiedBytes + = writeBytes ;
maximumBytesToCopy - = writeBytes ;
}
return totalCopiedBytes ;
}
#endregion Stream
2010-12-09 02:53:15 +00:00
public class QBasedComparer : IComparer
{
public int Compare ( Object x , Object y )
{
float qx = GetQ ( x ) ;
float qy = GetQ ( y ) ;
2011-02-12 19:02:42 +00:00
return qy . CompareTo ( qx ) ; // descending order
2010-12-09 02:53:15 +00:00
}
private float GetQ ( Object o )
{
// Example: image/png;q=0.9
2011-02-12 19:02:42 +00:00
float qvalue = 1F ;
2010-12-09 02:53:15 +00:00
if ( o is String )
{
string mime = ( string ) o ;
2011-02-12 19:02:42 +00:00
string [ ] parts = mime . Split ( ';' ) ;
2010-12-09 02:53:15 +00:00
if ( parts . Length > 1 )
{
2011-02-12 19:02:42 +00:00
string [ ] kvp = parts [ 1 ] . Split ( '=' ) ;
2010-12-09 02:53:15 +00:00
if ( kvp . Length = = 2 & & kvp [ 0 ] = = "q" )
2011-02-12 19:02:42 +00:00
float . TryParse ( kvp [ 1 ] , NumberStyles . Number , CultureInfo . InvariantCulture , out qvalue ) ;
2010-12-09 02:53:15 +00:00
}
}
2011-02-12 19:02:42 +00:00
return qvalue ;
2010-12-09 02:53:15 +00:00
}
}
/// <summary>
/// Takes the value of an Accept header and returns the preferred types
/// ordered by q value (if it exists).
/// Example input: image/jpg;q=0.7, image/png;q=0.8, image/jp2
/// Exmaple output: ["jp2", "png", "jpg"]
/// NOTE: This doesn't handle the semantics of *'s...
/// </summary>
/// <param name="accept"></param>
/// <returns></returns>
public static string [ ] GetPreferredImageTypes ( string accept )
{
2013-11-15 21:45:08 +00:00
if ( string . IsNullOrEmpty ( accept ) )
2010-12-09 02:53:15 +00:00
return new string [ 0 ] ;
string [ ] types = accept . Split ( new char [ ] { ',' } ) ;
if ( types . Length > 0 )
{
List < string > list = new List < string > ( types ) ;
list . RemoveAll ( delegate ( string s ) { return ! s . ToLower ( ) . StartsWith ( "image" ) ; } ) ;
ArrayList tlist = new ArrayList ( list ) ;
tlist . Sort ( new QBasedComparer ( ) ) ;
string [ ] result = new string [ tlist . Count ] ;
for ( int i = 0 ; i < tlist . Count ; i + + )
{
string mime = ( string ) tlist [ i ] ;
string [ ] parts = mime . Split ( new char [ ] { ';' } ) ;
string [ ] pair = parts [ 0 ] . Split ( new char [ ] { '/' } ) ;
if ( pair . Length = = 2 )
result [ i ] = pair [ 1 ] . ToLower ( ) ;
else // oops, we don't know what this is...
result [ i ] = pair [ 0 ] ;
}
return result ;
}
return new string [ 0 ] ;
}
2010-03-03 22:38:00 +00:00
}
2011-04-13 03:24:28 +00:00
public static class AsynchronousRestObjectRequester
{
private static readonly ILog m_log = LogManager . GetLogger ( MethodBase . GetCurrentMethod ( ) . DeclaringType ) ;
/// <summary>
/// Perform an asynchronous REST request.
/// </summary>
/// <param name="verb">GET or POST</param>
/// <param name="requestUrl"></param>
/// <param name="obj"></param>
/// <param name="action"></param>
/// <returns></returns>
///
/// <exception cref="System.Net.WebException">Thrown if we encounter a
/// network issue while posting the request. You'll want to make
/// sure you deal with this as they're not uncommon</exception>
/ /
public static void MakeRequest < TRequest , TResponse > ( string verb ,
string requestUrl , TRequest obj , Action < TResponse > action )
2012-09-13 22:15:10 +00:00
{
MakeRequest < TRequest , TResponse > ( verb , requestUrl , obj , action , 0 ) ;
}
public static void MakeRequest < TRequest , TResponse > ( string verb ,
string requestUrl , TRequest obj , Action < TResponse > action ,
int maxConnections )
2014-05-23 23:19:43 +00:00
{
MakeRequest < TRequest , TResponse > ( verb , requestUrl , obj , action , maxConnections , null ) ;
}
2015-09-02 18:54:53 +00:00
/// <summary>
/// Perform a synchronous REST request.
/// </summary>
/// <param name="verb"></param>
/// <param name="requestUrl"></param>
/// <param name="obj"></param>
/// <param name="pTimeout">
2015-09-03 17:39:08 +00:00
/// Request timeout in seconds. Timeout.Infinite indicates no timeout. If 0 is passed then the default HttpWebRequest timeout is used (100 seconds)
2015-09-02 18:54:53 +00:00
/// </param>
/// <param name="maxConnections"></param>
/// <returns>
2017-01-05 19:07:37 +00:00
/// The response. If there was an internal exception or the request timed out,
2015-09-02 18:54:53 +00:00
/// then the default(TResponse) is returned.
/// </returns>
2014-05-23 23:19:43 +00:00
public static void MakeRequest < TRequest , TResponse > ( string verb ,
string requestUrl , TRequest obj , Action < TResponse > action ,
int maxConnections , IServiceAuth auth )
2011-04-13 03:24:28 +00:00
{
2012-05-04 00:12:56 +00:00
int reqnum = WebUtil . RequestNumber + + ;
2012-09-20 21:36:47 +00:00
if ( WebUtil . DebugLevel > = 3 )
2014-04-24 11:21:05 +00:00
m_log . DebugFormat ( "[LOGHTTP]: HTTP OUT {0} AsynchronousRequestObject {1} to {2}" ,
2012-09-20 21:36:47 +00:00
reqnum , verb , requestUrl ) ;
2012-05-04 00:12:56 +00:00
int tickstart = Util . EnvironmentTickCount ( ) ;
2015-09-02 18:54:53 +00:00
int tickdata = 0 ;
2012-10-04 23:14:49 +00:00
int tickdiff = 0 ;
2012-05-04 00:12:56 +00:00
2011-04-13 03:24:28 +00:00
Type type = typeof ( TRequest ) ;
WebRequest request = WebRequest . Create ( requestUrl ) ;
2012-09-13 22:15:10 +00:00
HttpWebRequest ht = ( HttpWebRequest ) request ;
2014-05-23 23:19:43 +00:00
if ( auth ! = null )
auth . AddAuthorization ( ht . Headers ) ;
2012-09-13 22:15:10 +00:00
if ( maxConnections > 0 & & ht . ServicePoint . ConnectionLimit < maxConnections )
ht . ServicePoint . ConnectionLimit = maxConnections ;
2011-04-13 03:24:28 +00:00
TResponse deserial = default ( TResponse ) ;
request . Method = verb ;
2014-02-27 22:52:43 +00:00
2012-05-04 00:12:56 +00:00
MemoryStream buffer = null ;
2011-04-13 03:24:28 +00:00
2014-02-27 22:52:43 +00:00
try
2011-04-13 03:24:28 +00:00
{
2014-02-27 22:52:43 +00:00
if ( verb = = "POST" )
2011-04-13 03:24:28 +00:00
{
2014-02-27 22:52:43 +00:00
request . ContentType = "text/xml" ;
2011-04-13 03:24:28 +00:00
2014-02-27 22:52:43 +00:00
buffer = new MemoryStream ( ) ;
2011-04-13 03:24:28 +00:00
2014-02-27 22:52:43 +00:00
XmlWriterSettings settings = new XmlWriterSettings ( ) ;
settings . Encoding = Encoding . UTF8 ;
2013-06-12 20:34:20 +00:00
2014-02-27 22:52:43 +00:00
using ( XmlWriter writer = XmlWriter . Create ( buffer , settings ) )
{
XmlSerializer serializer = new XmlSerializer ( type ) ;
serializer . Serialize ( writer , obj ) ;
writer . Flush ( ) ;
}
2011-04-13 03:24:28 +00:00
2014-02-27 22:52:43 +00:00
int length = ( int ) buffer . Length ;
request . ContentLength = length ;
2013-11-28 21:07:14 +00:00
byte [ ] data = buffer . ToArray ( ) ;
2011-04-13 03:24:28 +00:00
2014-02-27 22:52:43 +00:00
if ( WebUtil . DebugLevel > = 5 )
2014-04-24 11:21:05 +00:00
WebUtil . LogOutgoingDetail ( "SEND" , reqnum , System . Text . Encoding . UTF8 . GetString ( data ) ) ;
2012-05-04 00:12:56 +00:00
2014-02-27 22:52:43 +00:00
request . BeginGetRequestStream ( delegate ( IAsyncResult res )
2011-04-13 03:24:28 +00:00
{
2014-02-27 22:52:43 +00:00
using ( Stream requestStream = request . EndGetRequestStream ( res ) )
2013-11-28 21:07:14 +00:00
requestStream . Write ( data , 0 , length ) ;
2014-02-27 22:52:43 +00:00
// capture how much time was spent writing
2015-09-03 17:39:08 +00:00
tickdata = Util . EnvironmentTickCountSubtract ( tickstart ) ;
2014-02-27 22:52:43 +00:00
request . BeginGetResponse ( delegate ( IAsyncResult ar )
2011-04-13 03:24:28 +00:00
{
2014-02-27 22:52:43 +00:00
using ( WebResponse response = request . EndGetResponse ( ar ) )
{
try
{
using ( Stream respStream = response . GetResponseStream ( ) )
2013-11-28 21:07:14 +00:00
{
2014-04-24 11:21:05 +00:00
deserial = XMLResponseHelper . LogAndDeserialize < TRequest , TResponse > (
reqnum , respStream , response . ContentLength ) ;
2013-11-28 21:07:14 +00:00
}
2014-02-27 22:52:43 +00:00
}
catch ( System . InvalidOperationException )
{
}
}
2011-04-13 03:24:28 +00:00
2014-02-27 22:52:43 +00:00
action ( deserial ) ;
2011-04-13 03:24:28 +00:00
2014-02-27 22:52:43 +00:00
} , null ) ;
2011-04-13 03:24:28 +00:00
} , null ) ;
2014-02-27 22:52:43 +00:00
}
else
2011-04-13 03:24:28 +00:00
{
2014-02-27 22:52:43 +00:00
request . BeginGetResponse ( delegate ( IAsyncResult res2 )
2011-04-13 03:24:28 +00:00
{
2012-05-04 00:12:56 +00:00
try
{
2014-02-27 22:52:43 +00:00
// If the server returns a 404, this appears to trigger a System.Net.WebException even though that isn't
// documented in MSDN
using ( WebResponse response = request . EndGetResponse ( res2 ) )
2017-01-05 19:07:37 +00:00
{
2014-02-27 22:52:43 +00:00
try
{
using ( Stream respStream = response . GetResponseStream ( ) )
2013-11-28 21:07:14 +00:00
{
2014-04-24 11:21:05 +00:00
deserial = XMLResponseHelper . LogAndDeserialize < TRequest , TResponse > (
reqnum , respStream , response . ContentLength ) ;
2013-11-28 21:07:14 +00:00
}
2014-02-27 22:52:43 +00:00
}
catch ( System . InvalidOperationException )
{
}
}
2012-05-04 00:12:56 +00:00
}
2014-02-27 22:52:43 +00:00
catch ( WebException e )
2011-04-13 03:24:28 +00:00
{
2014-02-27 22:52:43 +00:00
if ( e . Status = = WebExceptionStatus . ProtocolError )
2011-04-13 03:24:28 +00:00
{
2014-02-27 22:52:43 +00:00
if ( e . Response is HttpWebResponse )
{
using ( HttpWebResponse httpResponse = ( HttpWebResponse ) e . Response )
2017-01-05 19:07:37 +00:00
{
2014-02-27 22:52:43 +00:00
if ( httpResponse . StatusCode ! = HttpStatusCode . NotFound )
{
// We don't appear to be handling any other status codes, so log these feailures to that
// people don't spend unnecessary hours hunting phantom bugs.
m_log . DebugFormat (
"[ASYNC REQUEST]: Request {0} {1} failed with unexpected status code {2}" ,
verb , requestUrl , httpResponse . StatusCode ) ;
}
2013-02-27 00:21:02 +00:00
}
2012-05-04 00:12:56 +00:00
}
2011-04-13 03:24:28 +00:00
}
2014-02-27 22:52:43 +00:00
else
{
m_log . ErrorFormat (
"[ASYNC REQUEST]: Request {0} {1} failed with status {2} and message {3}" ,
verb , requestUrl , e . Status , e . Message ) ;
}
2011-04-13 03:24:28 +00:00
}
2014-02-27 22:52:43 +00:00
catch ( Exception e )
2012-05-04 00:12:56 +00:00
{
m_log . ErrorFormat (
2014-02-27 22:52:43 +00:00
"[ASYNC REQUEST]: Request {0} {1} failed with exception {2}{3}" ,
verb , requestUrl , e . Message , e . StackTrace ) ;
2012-05-04 00:12:56 +00:00
}
2017-01-05 19:07:37 +00:00
2014-02-27 22:52:43 +00:00
// m_log.DebugFormat("[ASYNC REQUEST]: Received {0}", deserial.ToString());
2012-05-04 00:12:56 +00:00
2014-02-27 22:52:43 +00:00
try
{
action ( deserial ) ;
}
catch ( Exception e )
{
m_log . ErrorFormat (
"[ASYNC REQUEST]: Request {0} {1} callback failed with exception {2}{3}" ,
verb , requestUrl , e . Message , e . StackTrace ) ;
}
2017-01-05 19:07:37 +00:00
2014-02-27 22:52:43 +00:00
} , null ) ;
}
2015-09-02 18:54:53 +00:00
tickdiff = Util . EnvironmentTickCountSubtract ( tickstart ) ;
2014-02-27 22:52:43 +00:00
if ( tickdiff > WebUtil . LongCallTime )
{
string originalRequest = null ;
if ( buffer ! = null )
2012-05-04 00:12:56 +00:00
{
2014-02-27 22:52:43 +00:00
originalRequest = Encoding . UTF8 . GetString ( buffer . ToArray ( ) ) ;
2011-04-13 03:24:28 +00:00
2014-02-27 22:52:43 +00:00
if ( originalRequest . Length > WebUtil . MaxRequestDiagLength )
originalRequest = originalRequest . Remove ( WebUtil . MaxRequestDiagLength ) ;
}
2015-09-02 18:54:53 +00:00
m_log . InfoFormat (
2014-04-24 11:21:05 +00:00
"[LOGHTTP]: Slow AsynchronousRequestObject request {0} {1} to {2} took {3}ms, {4}ms writing, {5}" ,
reqnum , verb , requestUrl , tickdiff , tickdata ,
2014-02-27 22:52:43 +00:00
originalRequest ) ;
}
else if ( WebUtil . DebugLevel > = 4 )
2011-04-13 03:24:28 +00:00
{
2015-09-03 17:39:08 +00:00
m_log . DebugFormat ( "[LOGHTTP]: HTTP OUT {0} took {1}ms, {2}ms writing" ,
reqnum , tickdiff , tickdata ) ;
2011-04-13 03:24:28 +00:00
}
2012-05-04 00:12:56 +00:00
}
2014-02-27 22:52:43 +00:00
finally
2017-01-05 19:07:37 +00:00
{
2014-02-27 22:52:43 +00:00
if ( buffer ! = null )
buffer . Dispose ( ) ;
2012-09-20 22:18:19 +00:00
}
2011-04-13 03:24:28 +00:00
}
}
public static class SynchronousRestFormsRequester
{
2012-05-04 00:12:56 +00:00
private static readonly ILog m_log = LogManager . GetLogger ( MethodBase . GetCurrentMethod ( ) . DeclaringType ) ;
2011-04-13 03:24:28 +00:00
/// <summary>
/// Perform a synchronous REST request.
/// </summary>
/// <param name="verb"></param>
/// <param name="requestUrl"></param>
/// <param name="obj"> </param>
2013-06-30 01:35:23 +00:00
/// <param name="timeoutsecs"> </param>
2011-04-13 03:24:28 +00:00
/// <returns></returns>
///
/// <exception cref="System.Net.WebException">Thrown if we encounter a network issue while posting
/// the request. You'll want to make sure you deal with this as they're not uncommon</exception>
2016-11-23 19:30:55 +00:00
public static string MakeRequest ( string verb , string requestUrl , string obj , int timeoutsecs = - 1 ,
IServiceAuth auth = null , bool keepalive = true )
2011-04-13 03:24:28 +00:00
{
2012-05-04 00:12:56 +00:00
int reqnum = WebUtil . RequestNumber + + ;
2012-09-20 21:36:47 +00:00
if ( WebUtil . DebugLevel > = 3 )
2014-04-24 11:21:05 +00:00
m_log . DebugFormat ( "[LOGHTTP]: HTTP OUT {0} SynchronousRestForms {1} to {2}" ,
2012-09-20 21:36:47 +00:00
reqnum , verb , requestUrl ) ;
2012-05-04 00:12:56 +00:00
int tickstart = Util . EnvironmentTickCount ( ) ;
int tickdata = 0 ;
2011-04-13 03:24:28 +00:00
WebRequest request = WebRequest . Create ( requestUrl ) ;
request . Method = verb ;
2013-06-30 01:35:23 +00:00
if ( timeoutsecs > 0 )
request . Timeout = timeoutsecs * 1000 ;
2016-11-23 19:30:55 +00:00
if ( ! keepalive & & request is HttpWebRequest )
( ( HttpWebRequest ) request ) . KeepAlive = false ;
2014-05-23 23:19:43 +00:00
if ( auth ! = null )
auth . AddAuthorization ( request . Headers ) ;
2011-04-13 03:24:28 +00:00
string respstring = String . Empty ;
2012-10-04 23:14:49 +00:00
int tickset = Util . EnvironmentTickCountSubtract ( tickstart ) ;
2011-04-13 03:24:28 +00:00
using ( MemoryStream buffer = new MemoryStream ( ) )
{
if ( ( verb = = "POST" ) | | ( verb = = "PUT" ) )
{
2011-05-08 23:51:04 +00:00
request . ContentType = "application/x-www-form-urlencoded" ;
2011-04-13 03:24:28 +00:00
int length = 0 ;
using ( StreamWriter writer = new StreamWriter ( buffer ) )
{
writer . Write ( obj ) ;
writer . Flush ( ) ;
}
length = ( int ) obj . Length ;
request . ContentLength = length ;
2013-11-28 21:07:14 +00:00
byte [ ] data = buffer . ToArray ( ) ;
2011-04-13 03:24:28 +00:00
2013-06-12 20:34:20 +00:00
if ( WebUtil . DebugLevel > = 5 )
2014-04-24 11:21:05 +00:00
WebUtil . LogOutgoingDetail ( "SEND" , reqnum , System . Text . Encoding . UTF8 . GetString ( data ) ) ;
2013-06-12 20:34:20 +00:00
2011-04-13 03:24:28 +00:00
try
{
2016-11-17 19:15:28 +00:00
using ( Stream requestStream = request . GetRequestStream ( ) )
requestStream . Write ( data , 0 , length ) ;
2011-04-13 03:24:28 +00:00
}
catch ( Exception e )
{
2014-03-27 07:43:03 +00:00
m_log . InfoFormat ( "[FORMS]: Error sending request to {0}: {1}. Request: {2}" , requestUrl , e . Message ,
2013-12-19 08:51:57 +00:00
obj . Length > WebUtil . MaxRequestDiagLength ? obj . Remove ( WebUtil . MaxRequestDiagLength ) : obj ) ;
throw e ;
2011-04-13 03:24:28 +00:00
}
finally
{
2012-05-04 00:12:56 +00:00
// capture how much time was spent writing
tickdata = Util . EnvironmentTickCountSubtract ( tickstart ) ;
2011-04-13 03:24:28 +00:00
}
}
try
{
using ( WebResponse resp = request . GetResponse ( ) )
{
if ( resp . ContentLength ! = 0 )
{
2013-12-19 08:51:57 +00:00
using ( Stream respStream = resp . GetResponseStream ( ) )
using ( StreamReader reader = new StreamReader ( respStream ) )
respstring = reader . ReadToEnd ( ) ;
2011-04-13 03:24:28 +00:00
}
}
}
2013-12-19 08:51:57 +00:00
catch ( Exception e )
2011-04-13 03:24:28 +00:00
{
2014-03-27 07:43:03 +00:00
m_log . InfoFormat ( "[FORMS]: Error receiving response from {0}: {1}. Request: {2}" , requestUrl , e . Message ,
2013-12-19 08:51:57 +00:00
obj . Length > WebUtil . MaxRequestDiagLength ? obj . Remove ( WebUtil . MaxRequestDiagLength ) : obj ) ;
throw e ;
2011-04-13 03:24:28 +00:00
}
}
2012-05-04 00:12:56 +00:00
int tickdiff = Util . EnvironmentTickCountSubtract ( tickstart ) ;
if ( tickdiff > WebUtil . LongCallTime )
2014-04-24 11:21:05 +00:00
{
2012-05-04 00:12:56 +00:00
m_log . InfoFormat (
2012-09-21 00:59:28 +00:00
"[FORMS]: Slow request {0} {1} {2} took {3}ms, {4}ms writing, {5}" ,
2012-05-04 00:12:56 +00:00
reqnum ,
verb ,
requestUrl ,
tickdiff ,
2012-10-04 23:14:49 +00:00
tickset ,
2012-05-04 00:12:56 +00:00
tickdata ,
obj . Length > WebUtil . MaxRequestDiagLength ? obj . Remove ( WebUtil . MaxRequestDiagLength ) : obj ) ;
2014-04-24 11:21:05 +00:00
}
2012-09-20 22:18:19 +00:00
else if ( WebUtil . DebugLevel > = 4 )
2014-04-24 11:21:05 +00:00
{
m_log . DebugFormat ( "[LOGHTTP]: HTTP OUT {0} took {1}ms, {2}ms writing" ,
2012-09-20 22:18:19 +00:00
reqnum , tickdiff , tickdata ) ;
2014-04-24 11:21:05 +00:00
}
2012-05-04 00:12:56 +00:00
2013-11-28 21:07:14 +00:00
if ( WebUtil . DebugLevel > = 5 )
2014-04-24 11:21:05 +00:00
WebUtil . LogResponseDetail ( reqnum , respstring ) ;
2013-11-28 21:07:14 +00:00
2011-04-13 03:24:28 +00:00
return respstring ;
}
2013-06-30 01:35:23 +00:00
2014-05-23 23:19:43 +00:00
public static string MakeRequest ( string verb , string requestUrl , string obj , IServiceAuth auth )
{
return MakeRequest ( verb , requestUrl , obj , - 1 , auth ) ;
}
2011-04-13 03:24:28 +00:00
}
public class SynchronousRestObjectRequester
{
2011-05-13 00:34:26 +00:00
private static readonly ILog m_log =
LogManager . GetLogger (
MethodBase . GetCurrentMethod ( ) . DeclaringType ) ;
2011-04-13 03:24:28 +00:00
/// <summary>
/// Perform a synchronous REST request.
/// </summary>
/// <param name="verb"></param>
/// <param name="requestUrl"></param>
2014-05-12 21:05:02 +00:00
/// <param name="obj"></param>
/// <returns>
/// The response. If there was an internal exception, then the default(TResponse) is returned.
/// </returns>
2011-04-13 03:24:28 +00:00
public static TResponse MakeRequest < TRequest , TResponse > ( string verb , string requestUrl , TRequest obj )
2012-09-13 22:15:10 +00:00
{
2014-05-13 21:21:20 +00:00
return MakeRequest < TRequest , TResponse > ( verb , requestUrl , obj , 0 ) ;
2012-09-13 22:15:10 +00:00
}
2014-05-23 23:19:43 +00:00
public static TResponse MakeRequest < TRequest , TResponse > ( string verb , string requestUrl , TRequest obj , IServiceAuth auth )
{
return MakeRequest < TRequest , TResponse > ( verb , requestUrl , obj , 0 , auth ) ;
}
2014-05-12 21:05:02 +00:00
/// <summary>
/// Perform a synchronous REST request.
/// </summary>
/// <param name="verb"></param>
/// <param name="requestUrl"></param>
/// <param name="obj"></param>
2014-05-13 21:21:20 +00:00
/// <param name="pTimeout">
/// Request timeout in milliseconds. Timeout.Infinite indicates no timeout. If 0 is passed then the default HttpWebRequest timeout is used (100 seconds)
/// </param>
2014-05-12 21:05:02 +00:00
/// <returns>
2017-01-05 19:07:37 +00:00
/// The response. If there was an internal exception or the request timed out,
2014-05-12 21:05:02 +00:00
/// then the default(TResponse) is returned.
/// </returns>
2012-09-13 22:15:10 +00:00
public static TResponse MakeRequest < TRequest , TResponse > ( string verb , string requestUrl , TRequest obj , int pTimeout )
{
return MakeRequest < TRequest , TResponse > ( verb , requestUrl , obj , pTimeout , 0 ) ;
}
2014-05-23 23:19:43 +00:00
public static TResponse MakeRequest < TRequest , TResponse > ( string verb , string requestUrl , TRequest obj , int pTimeout , IServiceAuth auth )
{
return MakeRequest < TRequest , TResponse > ( verb , requestUrl , obj , pTimeout , 0 , auth ) ;
}
2014-05-12 21:05:02 +00:00
/// Perform a synchronous REST request.
/// </summary>
/// <param name="verb"></param>
/// <param name="requestUrl"></param>
/// <param name="obj"></param>
2014-05-13 21:21:20 +00:00
/// <param name="pTimeout">
/// Request timeout in milliseconds. Timeout.Infinite indicates no timeout. If 0 is passed then the default HttpWebRequest timeout is used (100 seconds)
/// </param>
2014-05-12 21:05:02 +00:00
/// <param name="maxConnections"></param>
/// <returns>
2017-01-05 19:07:37 +00:00
/// The response. If there was an internal exception or the request timed out,
2014-05-12 21:05:02 +00:00
/// then the default(TResponse) is returned.
/// </returns>
2012-09-13 22:15:10 +00:00
public static TResponse MakeRequest < TRequest , TResponse > ( string verb , string requestUrl , TRequest obj , int pTimeout , int maxConnections )
2014-05-23 23:19:43 +00:00
{
return MakeRequest < TRequest , TResponse > ( verb , requestUrl , obj , pTimeout , maxConnections , null ) ;
}
/// <summary>
/// Perform a synchronous REST request.
/// </summary>
/// <param name="verb"></param>
/// <param name="requestUrl"></param>
/// <param name="obj"></param>
/// <param name="pTimeout">
/// Request timeout in milliseconds. Timeout.Infinite indicates no timeout. If 0 is passed then the default HttpWebRequest timeout is used (100 seconds)
/// </param>
/// <param name="maxConnections"></param>
/// <returns>
2017-01-05 19:07:37 +00:00
/// The response. If there was an internal exception or the request timed out,
2014-05-23 23:19:43 +00:00
/// then the default(TResponse) is returned.
/// </returns>
public static TResponse MakeRequest < TRequest , TResponse > ( string verb , string requestUrl , TRequest obj , int pTimeout , int maxConnections , IServiceAuth auth )
2011-04-13 03:24:28 +00:00
{
2012-05-04 00:12:56 +00:00
int reqnum = WebUtil . RequestNumber + + ;
2012-09-20 21:36:47 +00:00
if ( WebUtil . DebugLevel > = 3 )
2014-04-24 11:21:05 +00:00
m_log . DebugFormat ( "[LOGHTTP]: HTTP OUT {0} SynchronousRestObject {1} to {2}" ,
2012-09-20 21:36:47 +00:00
reqnum , verb , requestUrl ) ;
2012-05-04 00:12:56 +00:00
int tickstart = Util . EnvironmentTickCount ( ) ;
int tickdata = 0 ;
2011-04-13 03:24:28 +00:00
Type type = typeof ( TRequest ) ;
TResponse deserial = default ( TResponse ) ;
WebRequest request = WebRequest . Create ( requestUrl ) ;
2012-09-13 22:15:10 +00:00
HttpWebRequest ht = ( HttpWebRequest ) request ;
2014-05-13 21:21:20 +00:00
2014-05-23 23:19:43 +00:00
if ( auth ! = null )
auth . AddAuthorization ( ht . Headers ) ;
2014-05-13 21:21:20 +00:00
if ( pTimeout ! = 0 )
2015-09-09 22:17:18 +00:00
request . Timeout = pTimeout ;
2014-05-12 18:20:00 +00:00
2012-09-13 22:15:10 +00:00
if ( maxConnections > 0 & & ht . ServicePoint . ConnectionLimit < maxConnections )
ht . ServicePoint . ConnectionLimit = maxConnections ;
2011-04-13 03:24:28 +00:00
request . Method = verb ;
2012-05-04 00:12:56 +00:00
MemoryStream buffer = null ;
2011-04-13 03:24:28 +00:00
2014-02-27 22:52:43 +00:00
try
2011-04-13 03:24:28 +00:00
{
2014-02-27 22:52:43 +00:00
if ( ( verb = = "POST" ) | | ( verb = = "PUT" ) )
{
request . ContentType = "text/xml" ;
2011-04-13 03:24:28 +00:00
2014-02-27 22:52:43 +00:00
buffer = new MemoryStream ( ) ;
2011-04-13 03:24:28 +00:00
2014-02-27 22:52:43 +00:00
XmlWriterSettings settings = new XmlWriterSettings ( ) ;
settings . Encoding = Encoding . UTF8 ;
2011-04-13 03:24:28 +00:00
2014-02-27 22:52:43 +00:00
using ( XmlWriter writer = XmlWriter . Create ( buffer , settings ) )
{
XmlSerializer serializer = new XmlSerializer ( type ) ;
serializer . Serialize ( writer , obj ) ;
writer . Flush ( ) ;
}
2011-04-13 03:24:28 +00:00
2014-02-27 22:52:43 +00:00
int length = ( int ) buffer . Length ;
request . ContentLength = length ;
2013-11-28 21:07:14 +00:00
byte [ ] data = buffer . ToArray ( ) ;
2013-06-12 20:34:20 +00:00
2014-02-27 22:52:43 +00:00
if ( WebUtil . DebugLevel > = 5 )
2014-04-24 11:21:05 +00:00
WebUtil . LogOutgoingDetail ( "SEND" , reqnum , System . Text . Encoding . UTF8 . GetString ( data ) ) ;
2012-04-25 23:43:31 +00:00
2014-02-27 22:52:43 +00:00
try
{
using ( Stream requestStream = request . GetRequestStream ( ) )
2013-11-28 21:07:14 +00:00
requestStream . Write ( data , 0 , length ) ;
2014-02-27 22:52:43 +00:00
}
catch ( Exception e )
{
m_log . DebugFormat (
"[SynchronousRestObjectRequester]: Exception in making request {0} {1}: {2}{3}" ,
verb , requestUrl , e . Message , e . StackTrace ) ;
2012-05-04 00:12:56 +00:00
2014-02-27 22:52:43 +00:00
return deserial ;
}
finally
{
// capture how much time was spent writing
tickdata = Util . EnvironmentTickCountSubtract ( tickstart ) ;
}
2011-04-13 03:24:28 +00:00
}
2014-02-27 22:52:43 +00:00
try
2011-04-13 03:24:28 +00:00
{
2014-02-27 22:52:43 +00:00
using ( HttpWebResponse resp = ( HttpWebResponse ) request . GetResponse ( ) )
2011-04-13 03:24:28 +00:00
{
2014-02-27 22:52:43 +00:00
if ( resp . ContentLength ! = 0 )
{
using ( Stream respStream = resp . GetResponseStream ( ) )
{
2014-04-24 11:21:05 +00:00
deserial = XMLResponseHelper . LogAndDeserialize < TRequest , TResponse > (
reqnum , respStream , resp . ContentLength ) ;
2014-02-27 22:52:43 +00:00
}
}
else
2013-02-27 00:21:02 +00:00
{
2014-02-27 22:52:43 +00:00
m_log . DebugFormat (
"[SynchronousRestObjectRequester]: Oops! no content found in response stream from {0} {1}" ,
verb , requestUrl ) ;
2013-02-27 00:21:02 +00:00
}
2011-04-13 03:24:28 +00:00
}
2014-02-27 22:52:43 +00:00
}
catch ( WebException e )
{
using ( HttpWebResponse hwr = ( HttpWebResponse ) e . Response )
2012-04-25 23:43:31 +00:00
{
2014-05-23 23:19:43 +00:00
if ( hwr ! = null )
{
if ( hwr . StatusCode = = HttpStatusCode . NotFound )
return deserial ;
if ( hwr . StatusCode = = HttpStatusCode . Unauthorized )
{
m_log . Error ( string . Format (
"[SynchronousRestObjectRequester]: Web request {0} requires authentication " ,
requestUrl ) ) ;
return deserial ;
}
}
2014-02-27 22:52:43 +00:00
else
2014-04-01 12:00:22 +00:00
m_log . Error ( string . Format (
"[SynchronousRestObjectRequester]: WebException for {0} {1} {2} " ,
verb , requestUrl , typeof ( TResponse ) . ToString ( ) ) , e ) ;
2012-04-25 23:43:31 +00:00
}
2011-04-13 03:24:28 +00:00
}
2014-02-27 22:52:43 +00:00
catch ( System . InvalidOperationException )
2013-02-27 00:21:02 +00:00
{
2014-02-27 22:52:43 +00:00
// This is what happens when there is invalid XML
m_log . DebugFormat (
"[SynchronousRestObjectRequester]: Invalid XML from {0} {1} {2}" ,
verb , requestUrl , typeof ( TResponse ) . ToString ( ) ) ;
}
catch ( Exception e )
{
2014-04-01 12:00:22 +00:00
m_log . Debug ( string . Format (
"[SynchronousRestObjectRequester]: Exception on response from {0} {1} " ,
verb , requestUrl ) , e ) ;
2013-02-27 00:21:02 +00:00
}
2012-05-04 00:12:56 +00:00
2014-02-27 22:52:43 +00:00
int tickdiff = Util . EnvironmentTickCountSubtract ( tickstart ) ;
if ( tickdiff > WebUtil . LongCallTime )
2012-05-04 00:12:56 +00:00
{
2014-02-27 22:52:43 +00:00
string originalRequest = null ;
2012-05-04 00:12:56 +00:00
2014-02-27 22:52:43 +00:00
if ( buffer ! = null )
{
originalRequest = Encoding . UTF8 . GetString ( buffer . ToArray ( ) ) ;
2012-05-04 00:12:56 +00:00
2014-02-27 22:52:43 +00:00
if ( originalRequest . Length > WebUtil . MaxRequestDiagLength )
originalRequest = originalRequest . Remove ( WebUtil . MaxRequestDiagLength ) ;
}
m_log . InfoFormat (
2014-04-24 11:21:05 +00:00
"[LOGHTTP]: Slow SynchronousRestObject request {0} {1} to {2} took {3}ms, {4}ms writing, {5}" ,
reqnum , verb , requestUrl , tickdiff , tickdata ,
2014-02-27 22:52:43 +00:00
originalRequest ) ;
}
else if ( WebUtil . DebugLevel > = 4 )
{
2014-04-24 11:21:05 +00:00
m_log . DebugFormat ( "[LOGHTTP]: HTTP OUT {0} took {1}ms, {2}ms writing" ,
2014-02-27 22:52:43 +00:00
reqnum , tickdiff , tickdata ) ;
}
2012-05-04 00:12:56 +00:00
}
2014-02-27 22:52:43 +00:00
finally
2012-09-20 22:18:19 +00:00
{
2014-02-27 22:52:43 +00:00
if ( buffer ! = null )
buffer . Dispose ( ) ;
2012-09-20 22:18:19 +00:00
}
2012-05-04 00:12:56 +00:00
2011-04-13 03:24:28 +00:00
return deserial ;
}
2017-01-05 19:07:37 +00:00
2014-03-27 15:46:37 +00:00
public static class XMLResponseHelper
{
2014-04-24 11:21:05 +00:00
public static TResponse LogAndDeserialize < TRequest , TResponse > ( int reqnum , Stream respStream , long contentLength )
2014-03-27 15:46:37 +00:00
{
XmlSerializer deserializer = new XmlSerializer ( typeof ( TResponse ) ) ;
if ( WebUtil . DebugLevel > = 5 )
{
byte [ ] data = new byte [ contentLength ] ;
Util . ReadStream ( respStream , data ) ;
2014-04-24 11:21:05 +00:00
WebUtil . LogResponseDetail ( reqnum , System . Text . Encoding . UTF8 . GetString ( data ) ) ;
2014-03-27 15:46:37 +00:00
using ( MemoryStream temp = new MemoryStream ( data ) )
return ( TResponse ) deserializer . Deserialize ( temp ) ;
}
else
{
return ( TResponse ) deserializer . Deserialize ( respStream ) ;
}
}
}
2011-04-13 03:24:28 +00:00
}
2014-04-24 11:21:05 +00:00
2017-01-05 19:07:37 +00:00
2014-04-24 11:21:05 +00:00
public static class XMLRPCRequester
{
private static readonly ILog m_log = LogManager . GetLogger ( MethodBase . GetCurrentMethod ( ) . DeclaringType ) ;
public static Hashtable SendRequest ( Hashtable ReqParams , string method , string url )
{
int reqnum = WebUtil . RequestNumber + + ;
if ( WebUtil . DebugLevel > = 3 )
m_log . DebugFormat ( "[LOGHTTP]: HTTP OUT {0} XML-RPC '{1}' to {2}" ,
reqnum , method , url ) ;
int tickstart = Util . EnvironmentTickCount ( ) ;
string responseStr = null ;
try
{
ArrayList SendParams = new ArrayList ( ) ;
SendParams . Add ( ReqParams ) ;
XmlRpcRequest Req = new XmlRpcRequest ( method , SendParams ) ;
if ( WebUtil . DebugLevel > = 5 )
{
string str = Req . ToString ( ) ;
str = XElement . Parse ( str ) . ToString ( SaveOptions . DisableFormatting ) ;
WebUtil . LogOutgoingDetail ( "SEND" , reqnum , str ) ;
}
XmlRpcResponse Resp = Req . Send ( url , 30000 ) ;
try
{
responseStr = Resp . ToString ( ) ;
responseStr = XElement . Parse ( responseStr ) . ToString ( SaveOptions . DisableFormatting ) ;
if ( WebUtil . DebugLevel > = 5 )
WebUtil . LogResponseDetail ( reqnum , responseStr ) ;
}
catch ( Exception e )
{
m_log . Error ( "Error parsing XML-RPC response" , e ) ;
}
2017-01-05 19:07:37 +00:00
2014-04-24 11:21:05 +00:00
if ( Resp . IsFault )
{
m_log . DebugFormat (
"[LOGHTTP]: XML-RPC request {0} '{1}' to {2} FAILED: FaultCode={3}, FaultMessage={4}" ,
reqnum , method , url , Resp . FaultCode , Resp . FaultString ) ;
return null ;
}
Hashtable RespData = ( Hashtable ) Resp . Value ;
return RespData ;
}
finally
{
int tickdiff = Util . EnvironmentTickCountSubtract ( tickstart ) ;
if ( tickdiff > WebUtil . LongCallTime )
{
m_log . InfoFormat (
"[LOGHTTP]: Slow XML-RPC request {0} '{1}' to {2} took {3}ms, {4}" ,
reqnum , method , url , tickdiff ,
responseStr ! = null
? ( responseStr . Length > WebUtil . MaxRequestDiagLength ? responseStr . Remove ( WebUtil . MaxRequestDiagLength ) : responseStr )
: "" ) ;
}
else if ( WebUtil . DebugLevel > = 4 )
{
m_log . DebugFormat ( "[LOGHTTP]: HTTP OUT {0} took {1}ms" , reqnum , tickdiff ) ;
}
}
}
}
2013-11-28 21:07:14 +00:00
}