From d00f73c3a4cac77c97dcf4df1613fb85a516ffb4 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Fri, 4 Sep 2015 14:39:23 -0700 Subject: Deleted OpenSim.Framework.Communications. Moved its two remaining files to OpenSim.Framework. --- .../Framework/Communications/OutboundUrlFilter.cs | 256 -------- .../Communications/Properties/AssemblyInfo.cs | 65 -- OpenSim/Framework/Communications/RestClient.cs | 676 --------------------- 3 files changed, 997 deletions(-) delete mode 100644 OpenSim/Framework/Communications/OutboundUrlFilter.cs delete mode 100644 OpenSim/Framework/Communications/Properties/AssemblyInfo.cs delete mode 100644 OpenSim/Framework/Communications/RestClient.cs (limited to 'OpenSim/Framework/Communications') diff --git a/OpenSim/Framework/Communications/OutboundUrlFilter.cs b/OpenSim/Framework/Communications/OutboundUrlFilter.cs deleted file mode 100644 index 8b572d1..0000000 --- a/OpenSim/Framework/Communications/OutboundUrlFilter.cs +++ /dev/null @@ -1,256 +0,0 @@ -/* - * 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; -using System.Collections.Generic; -using System.Linq; -using System.Net; -using System.Reflection; -using log4net; -using LukeSkywalker.IPNetwork; -using Nini.Config; - -namespace OpenSim.Framework.Communications -{ - public class OutboundUrlFilter - { - private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - - public string Name { get; private set; } - - private List m_blacklistNetworks; - private List m_blacklistEndPoints; - - private List m_blacklistExceptionNetworks; - private List m_blacklistExceptionEndPoints; - - public OutboundUrlFilter( - string name, - List blacklistNetworks, List blacklistEndPoints, - List blacklistExceptionNetworks, List blacklistExceptionEndPoints) - { - Name = name; - - m_blacklistNetworks = blacklistNetworks; - m_blacklistEndPoints = blacklistEndPoints; - m_blacklistExceptionNetworks = blacklistExceptionNetworks; - m_blacklistExceptionEndPoints = blacklistExceptionEndPoints; - } - - /// - /// Initializes a new instance of the class. - /// - /// Name of the filter for logging purposes. - /// Filter configuration - public OutboundUrlFilter(string name, IConfigSource config) - { - Name = name; - - string configBlacklist - = "0.0.0.0/8|10.0.0.0/8|100.64.0.0/10|127.0.0.0/8|169.254.0.0/16|172.16.0.0/12|192.0.0.0/24|192.0.2.0/24|192.88.99.0/24|192.168.0.0/16|198.18.0.0/15|198.51.100.0/24|203.0.113.0/24|224.0.0.0/4|240.0.0.0/4|255.255.255.255/32"; - string configBlacklistExceptions = ""; - - IConfig networkConfig = config.Configs["Network"]; - - if (networkConfig != null) - { - configBlacklist = networkConfig.GetString("OutboundDisallowForUserScripts", configBlacklist); - configBlacklistExceptions - = networkConfig.GetString("OutboundDisallowForUserScriptsExcept", configBlacklistExceptions); - } - - m_log.DebugFormat( - "[OUTBOUND URL FILTER]: OutboundDisallowForUserScripts for {0} is [{1}]", Name, configBlacklist); - m_log.DebugFormat( - "[OUTBOUND URL FILTER]: OutboundDisallowForUserScriptsExcept for {0} is [{1}]", Name, configBlacklistExceptions); - - OutboundUrlFilter.ParseConfigList( - configBlacklist, Name, out m_blacklistNetworks, out m_blacklistEndPoints); - OutboundUrlFilter.ParseConfigList( - configBlacklistExceptions, Name, out m_blacklistExceptionNetworks, out m_blacklistExceptionEndPoints); - } - - private static void ParseConfigList( - string fullConfigEntry, string filterName, out List networks, out List endPoints) - { - // Parse blacklist - string[] configBlacklistEntries - = fullConfigEntry.Split(new char[] { '|' }, StringSplitOptions.RemoveEmptyEntries); - - configBlacklistEntries = configBlacklistEntries.Select(e => e.Trim()).ToArray(); - - networks = new List(); - endPoints = new List(); - - foreach (string configEntry in configBlacklistEntries) - { - if (configEntry.Contains("/")) - { - IPNetwork network; - - if (!IPNetwork.TryParse(configEntry, out network)) - { - m_log.ErrorFormat( - "[OUTBOUND URL FILTER]: Entry [{0}] is invalid network for {1}", configEntry, filterName); - - continue; - } - - networks.Add(network); - } - else - { - Uri configEntryUri; - - if (!Uri.TryCreate("http://" + configEntry, UriKind.Absolute, out configEntryUri)) - { - m_log.ErrorFormat( - "[OUTBOUND URL FILTER]: EndPoint entry [{0}] is invalid endpoint for {1}", - configEntry, filterName); - - continue; - } - - IPAddress[] addresses = Dns.GetHostAddresses(configEntryUri.Host); - - foreach (IPAddress addr in addresses) - { - if (addr.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork) - { - // m_log.DebugFormat("[OUTBOUND URL FILTER]: Found address [{0}] in config", addr); - - IPEndPoint configEntryEp = new IPEndPoint(addr, configEntryUri.Port); - endPoints.Add(configEntryEp); - - // m_log.DebugFormat("[OUTBOUND URL FILTER]: Added blacklist exception [{0}]", configEntryEp); - } - } - } - } - } - - /// - /// Determines if an url is in a list of networks and endpoints. - /// - /// - /// IP address - /// - /// Networks. - /// End points. - /// Filter name. - private static bool IsInNetwork( - IPAddress addr, int port, List networks, List endPoints, string filterName) - { - foreach (IPNetwork ipn in networks) - { -// m_log.DebugFormat( -// "[OUTBOUND URL FILTER]: Checking [{0}] against network [{1}]", addr, ipn); - - if (IPNetwork.Contains(ipn, addr)) - { -// m_log.DebugFormat( -// "[OUTBOUND URL FILTER]: Found [{0}] in network [{1}]", addr, ipn); - - return true; - } - } - - // m_log.DebugFormat("[OUTBOUND URL FILTER]: Found address [{0}]", addr); - - foreach (IPEndPoint ep in endPoints) - { -// m_log.DebugFormat( -// "[OUTBOUND URL FILTER]: Checking [{0}:{1}] against endpoint [{2}]", -// addr, port, ep); - - if (addr.Equals(ep.Address) && port == ep.Port) - { -// m_log.DebugFormat( -// "[OUTBOUND URL FILTER]: Found [{0}:{1}] in endpoint [{2}]", addr, port, ep); - - return true; - } - } - -// m_log.DebugFormat("[OUTBOUND URL FILTER]: Did not find [{0}:{1}] in list", addr, port); - - return false; - } - - /// - /// Checks whether the given url is allowed by the filter. - /// - /// - public bool CheckAllowed(Uri url) - { - bool allowed = true; - - // Check that we are permitted to make calls to this endpoint. - bool foundIpv4Address = false; - - IPAddress[] addresses = Dns.GetHostAddresses(url.Host); - - foreach (IPAddress addr in addresses) - { - if (addr.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork) - { -// m_log.DebugFormat("[OUTBOUND URL FILTER]: Found address [{0}]", addr); - - foundIpv4Address = true; - - // Check blacklist - if (OutboundUrlFilter.IsInNetwork(addr, url.Port, m_blacklistNetworks, m_blacklistEndPoints, Name)) - { -// m_log.DebugFormat("[OUTBOUND URL FILTER]: Found [{0}] in blacklist for {1}", url, Name); - - // Check blacklist exceptions - allowed - = OutboundUrlFilter.IsInNetwork( - addr, url.Port, m_blacklistExceptionNetworks, m_blacklistExceptionEndPoints, Name); - -// if (allowed) -// m_log.DebugFormat("[OUTBOUND URL FILTER]: Found [{0}] in whitelist for {1}", url, Name); - } - } - - // Found at least one address in a blacklist and not a blacklist exception - if (!allowed) - return false; -// else -// m_log.DebugFormat("[OUTBOUND URL FILTER]: URL [{0}] not in blacklist for {1}", url, Name); - } - - // We do not know how to handle IPv6 securely yet. - if (!foundIpv4Address) - return false; - -// m_log.DebugFormat("[OUTBOUND URL FILTER]: Allowing request [{0}]", url); - - return allowed; - } - } -} \ No newline at end of file diff --git a/OpenSim/Framework/Communications/Properties/AssemblyInfo.cs b/OpenSim/Framework/Communications/Properties/AssemblyInfo.cs deleted file mode 100644 index b398167..0000000 --- a/OpenSim/Framework/Communications/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,65 +0,0 @@ -/* - * 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.Reflection; -using System.Runtime.InteropServices; - -// General information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. - -[assembly : AssemblyTitle("OpenSim.Framework.Communications")] -[assembly : AssemblyDescription("")] -[assembly : AssemblyConfiguration("")] -[assembly : AssemblyCompany("http://opensimulator.org")] -[assembly : AssemblyProduct("OpenSim")] -[assembly : AssemblyCopyright("Copyright (c) OpenSimulator.org Developers")] -[assembly : AssemblyTrademark("")] -[assembly : AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. - -[assembly : ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM - -[assembly : Guid("13e7c396-78a9-4a5c-baf2-6f980ea75d95")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Revision and Build Numbers -// by using the '*' as shown below: - -[assembly : AssemblyVersion("0.8.2.*")] - diff --git a/OpenSim/Framework/Communications/RestClient.cs b/OpenSim/Framework/Communications/RestClient.cs deleted file mode 100644 index ff7cb4d..0000000 --- a/OpenSim/Framework/Communications/RestClient.cs +++ /dev/null @@ -1,676 +0,0 @@ -/* - * 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; -using System.Collections.Generic; -using System.IO; -using System.Net; -using System.Reflection; -using System.Text; -using System.Threading; -using System.Web; -using log4net; - -using OpenSim.Framework.ServiceAuth; - -namespace OpenSim.Framework.Communications -{ - /// - /// Implementation of a generic REST client - /// - /// - /// This class is a generic implementation of a REST (Representational State Transfer) web service. This - /// class is designed to execute both synchronously and asynchronously. - /// - /// Internally the implementation works as a two stage asynchronous web-client. - /// When the request is initiated, RestClient will query asynchronously for for a web-response, - /// sleeping until the initial response is returned by the server. Once the initial response is retrieved - /// the second stage of asynchronous requests will be triggered, in an attempt to read of the response - /// object into a memorystream as a sequence of asynchronous reads. - /// - /// The asynchronisity of RestClient is designed to move as much processing into the back-ground, allowing - /// other threads to execute, while it waits for a response from the web-service. RestClient itself can be - /// invoked by the caller in either synchronous mode or asynchronous modes. - /// - public class RestClient : IDisposable - { - private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - - // private string realuri; - - #region member variables - - /// - /// The base Uri of the web-service e.g. http://www.google.com - /// - private string _url; - - /// - /// Path elements of the query - /// - private List _pathElements = new List(); - - /// - /// Parameter elements of the query, e.g. min=34 - /// - private Dictionary _parameterElements = new Dictionary(); - - /// - /// Request method. E.g. GET, POST, PUT or DELETE - /// - private string _method; - - /// - /// Temporary buffer used to store bytes temporarily as they come in from the server - /// - private byte[] _readbuf; - - /// - /// MemoryStream representing the resulting resource - /// - private Stream _resource; - - /// - /// WebRequest object, held as a member variable - /// - private HttpWebRequest _request; - - /// - /// WebResponse object, held as a member variable, so we can close it - /// - private HttpWebResponse _response; - - /// - /// This flag will help block the main synchroneous method, in case we run in synchroneous mode - /// - //public static ManualResetEvent _allDone = new ManualResetEvent(false); - - /// - /// Default time out period - /// - //private const int DefaultTimeout = 10*1000; // 10 seconds timeout - - /// - /// Default Buffer size of a block requested from the web-server - /// - private const int BufferSize = 4096; // Read blocks of 4 KB. - - - /// - /// if an exception occours during async processing, we need to save it, so it can be - /// rethrown on the primary thread; - /// - private Exception _asyncException; - - #endregion member variables - - #region constructors - - /// - /// Instantiate a new RestClient - /// - /// Web-service to query, e.g. http://osgrid.org:8003 - public RestClient(string url) - { - _url = url; - _readbuf = new byte[BufferSize]; - _resource = new MemoryStream(); - _request = null; - _response = null; - _lock = new object(); - } - - private object _lock; - - #endregion constructors - - - #region Dispose - - private bool disposed = false; - - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - protected virtual void Dispose(bool disposing) - { - if (disposed) - return; - - if (disposing) - { - _resource.Dispose(); - } - - disposed = true; - } - - #endregion Dispose - - - /// - /// Add a path element to the query, e.g. assets - /// - /// path entry - public void AddResourcePath(string element) - { - if (isSlashed(element)) - _pathElements.Add(element.Substring(0, element.Length - 1)); - else - _pathElements.Add(element); - } - - /// - /// Add a query parameter to the Url - /// - /// Name of the parameter, e.g. min - /// Value of the parameter, e.g. 42 - public void AddQueryParameter(string name, string value) - { - try - { - _parameterElements.Add(HttpUtility.UrlEncode(name), HttpUtility.UrlEncode(value)); - } - catch (ArgumentException) - { - m_log.Error("[REST]: Query parameter " + name + " is already added."); - } - catch (Exception e) - { - m_log.Error("[REST]: An exception was raised adding query parameter to dictionary. Exception: {0}",e); - } - } - - /// - /// Add a query parameter to the Url - /// - /// Name of the parameter, e.g. min - public void AddQueryParameter(string name) - { - try - { - _parameterElements.Add(HttpUtility.UrlEncode(name), null); - } - catch (ArgumentException) - { - m_log.Error("[REST]: Query parameter " + name + " is already added."); - } - catch (Exception e) - { - m_log.Error("[REST]: An exception was raised adding query parameter to dictionary. Exception: {0}",e); - } - } - - /// - /// Web-Request method, e.g. GET, PUT, POST, DELETE - /// - public string RequestMethod - { - get { return _method; } - set { _method = value; } - } - - /// - /// True if string contains a trailing slash '/' - /// - /// string to be examined - /// true if slash is present - private static bool isSlashed(string s) - { - return s.Substring(s.Length - 1, 1) == "/"; - } - - /// - /// Build a Uri based on the initial Url, path elements and parameters - /// - /// fully constructed Uri - private Uri buildUri() - { - StringBuilder sb = new StringBuilder(); - sb.Append(_url); - - foreach (string e in _pathElements) - { - sb.Append("/"); - sb.Append(e); - } - - bool firstElement = true; - foreach (KeyValuePair kv in _parameterElements) - { - if (firstElement) - { - sb.Append("?"); - firstElement = false; - } - else - sb.Append("&"); - - sb.Append(kv.Key); - if (!string.IsNullOrEmpty(kv.Value)) - { - sb.Append("="); - sb.Append(kv.Value); - } - } - // realuri = sb.ToString(); - //m_log.InfoFormat("[REST CLIENT]: RestURL: {0}", realuri); - return new Uri(sb.ToString()); - } - - #region Async communications with server - - /// - /// Async method, invoked when a block of data has been received from the service - /// - /// - private void StreamIsReadyDelegate(IAsyncResult ar) - { - try - { - Stream s = (Stream) ar.AsyncState; - int read = s.EndRead(ar); - - if (read > 0) - { - _resource.Write(_readbuf, 0, read); - // IAsyncResult asynchronousResult = - // s.BeginRead(_readbuf, 0, BufferSize, new AsyncCallback(StreamIsReadyDelegate), s); - s.BeginRead(_readbuf, 0, BufferSize, new AsyncCallback(StreamIsReadyDelegate), s); - - // TODO! Implement timeout, without killing the server - //ThreadPool.RegisterWaitForSingleObject(asynchronousResult.AsyncWaitHandle, new WaitOrTimerCallback(TimeoutCallback), _request, DefaultTimeout, true); - } - else - { - s.Close(); - //_allDone.Set(); - } - } - catch (Exception e) - { - //_allDone.Set(); - _asyncException = e; - } - } - - #endregion Async communications with server - - /// - /// Perform a synchronous request - /// - public Stream Request() - { - return Request(null); - } - - /// - /// Perform a synchronous request - /// - public Stream Request(IServiceAuth auth) - { - lock (_lock) - { - _request = (HttpWebRequest) WebRequest.Create(buildUri()); - _request.KeepAlive = false; - _request.ContentType = "application/xml"; - _request.Timeout = 200000; - _request.Method = RequestMethod; - _asyncException = null; - if (auth != null) - auth.AddAuthorization(_request.Headers); - - int reqnum = WebUtil.RequestNumber++; - if (WebUtil.DebugLevel >= 3) - m_log.DebugFormat("[LOGHTTP]: HTTP OUT {0} REST {1} to {2}", reqnum, _request.Method, _request.RequestUri); - -// IAsyncResult responseAsyncResult = _request.BeginGetResponse(new AsyncCallback(ResponseIsReadyDelegate), _request); - - try - { - using (_response = (HttpWebResponse) _request.GetResponse()) - { - using (Stream src = _response.GetResponseStream()) - { - int length = src.Read(_readbuf, 0, BufferSize); - while (length > 0) - { - _resource.Write(_readbuf, 0, length); - length = src.Read(_readbuf, 0, BufferSize); - } - - // TODO! Implement timeout, without killing the server - // this line implements the timeout, if there is a timeout, the callback fires and the request becomes aborted - //ThreadPool.RegisterWaitForSingleObject(responseAsyncResult.AsyncWaitHandle, new WaitOrTimerCallback(TimeoutCallback), _request, DefaultTimeout, true); - - // _allDone.WaitOne(); - } - } - } - catch (WebException e) - { - using (HttpWebResponse errorResponse = e.Response as HttpWebResponse) - { - if (null != errorResponse && HttpStatusCode.NotFound == errorResponse.StatusCode) - { - // This is often benign. E.g., requesting a missing asset will return 404. - m_log.DebugFormat("[REST CLIENT] Resource not found (404): {0}", _request.Address.ToString()); - } - else - { - m_log.Error(string.Format("[REST CLIENT] Error fetching resource from server: {0} ", _request.Address.ToString()), e); - } - } - - return null; - } - - if (_asyncException != null) - throw _asyncException; - - if (_resource != null) - { - _resource.Flush(); - _resource.Seek(0, SeekOrigin.Begin); - } - - if (WebUtil.DebugLevel >= 5) - WebUtil.LogResponseDetail(reqnum, _resource); - - return _resource; - } - } - - public Stream Request(Stream src, IServiceAuth auth) - { - _request = (HttpWebRequest) WebRequest.Create(buildUri()); - _request.KeepAlive = false; - _request.ContentType = "application/xml"; - _request.Timeout = 900000; - _request.Method = RequestMethod; - _asyncException = null; - _request.ContentLength = src.Length; - if (auth != null) - auth.AddAuthorization(_request.Headers); - - src.Seek(0, SeekOrigin.Begin); - - int reqnum = WebUtil.RequestNumber++; - if (WebUtil.DebugLevel >= 3) - m_log.DebugFormat("[LOGHTTP]: HTTP OUT {0} REST {1} to {2}", reqnum, _request.Method, _request.RequestUri); - if (WebUtil.DebugLevel >= 5) - WebUtil.LogOutgoingDetail(string.Format("SEND {0}: ", reqnum), src); - - Stream dst = _request.GetRequestStream(); - - byte[] buf = new byte[1024]; - int length = src.Read(buf, 0, 1024); - while (length > 0) - { - dst.Write(buf, 0, length); - length = src.Read(buf, 0, 1024); - } - - try - { - _response = (HttpWebResponse)_request.GetResponse(); - } - catch (WebException e) - { - m_log.WarnFormat("[REST]: Request {0} {1} failed with status {2} and message {3}", - RequestMethod, _request.RequestUri, e.Status, e.Message); - return null; - } - catch (Exception e) - { - m_log.WarnFormat( - "[REST]: Request {0} {1} failed with exception {2} {3}", - RequestMethod, _request.RequestUri, e.Message, e.StackTrace); - return null; - } - - if (WebUtil.DebugLevel >= 5) - { - using (Stream responseStream = _response.GetResponseStream()) - { - using (StreamReader reader = new StreamReader(responseStream)) - { - string responseStr = reader.ReadToEnd(); - WebUtil.LogResponseDetail(reqnum, responseStr); - } - } - } - - _response.Close(); - -// IAsyncResult responseAsyncResult = _request.BeginGetResponse(new AsyncCallback(ResponseIsReadyDelegate), _request); - - // TODO! Implement timeout, without killing the server - // this line implements the timeout, if there is a timeout, the callback fires and the request becomes aborted - //ThreadPool.RegisterWaitForSingleObject(responseAsyncResult.AsyncWaitHandle, new WaitOrTimerCallback(TimeoutCallback), _request, DefaultTimeout, true); - - return null; - } - - #region Async Invocation - - public IAsyncResult BeginRequest(AsyncCallback callback, object state) - { - /// - /// In case, we are invoked asynchroneously this object will keep track of the state - /// - AsyncResult ar = new AsyncResult(callback, state); - Util.FireAndForget(RequestHelper, ar, "RestClient.BeginRequest"); - return ar; - } - - public Stream EndRequest(IAsyncResult asyncResult) - { - AsyncResult ar = (AsyncResult) asyncResult; - - // Wait for operation to complete, then return result or - // throw exception - return ar.EndInvoke(); - } - - private void RequestHelper(Object asyncResult) - { - // We know that it's really an AsyncResult object - AsyncResult ar = (AsyncResult) asyncResult; - try - { - // Perform the operation; if sucessful set the result - Stream s = Request(null); - ar.SetAsCompleted(s, false); - } - catch (Exception e) - { - // If operation fails, set the exception - ar.HandleException(e, false); - } - } - - #endregion Async Invocation - } - - internal class SimpleAsyncResult : IAsyncResult - { - private readonly AsyncCallback m_callback; - - /// - /// Is process completed? - /// - /// Should really be boolean, but VolatileRead has no boolean method - private byte m_completed; - - /// - /// Did process complete synchronously? - /// - /// I have a hard time imagining a scenario where this is the case, again, same issue about - /// booleans and VolatileRead as m_completed - /// - private byte m_completedSynchronously; - - private readonly object m_asyncState; - private ManualResetEvent m_waitHandle; - private Exception m_exception; - - internal SimpleAsyncResult(AsyncCallback cb, object state) - { - m_callback = cb; - m_asyncState = state; - m_completed = 0; - m_completedSynchronously = 1; - } - - #region IAsyncResult Members - - public object AsyncState - { - get { return m_asyncState; } - } - - public WaitHandle AsyncWaitHandle - { - get - { - if (m_waitHandle == null) - { - bool done = IsCompleted; - ManualResetEvent mre = new ManualResetEvent(done); - if (Interlocked.CompareExchange(ref m_waitHandle, mre, null) != null) - { - mre.Close(); - } - else - { - if (!done && IsCompleted) - { - m_waitHandle.Set(); - } - } - } - - return m_waitHandle; - } - } - - - public bool CompletedSynchronously - { - get { return Thread.VolatileRead(ref m_completedSynchronously) == 1; } - } - - - public bool IsCompleted - { - get { return Thread.VolatileRead(ref m_completed) == 1; } - } - - #endregion - - #region class Methods - - internal void SetAsCompleted(bool completedSynchronously) - { - m_completed = 1; - if (completedSynchronously) - m_completedSynchronously = 1; - else - m_completedSynchronously = 0; - - SignalCompletion(); - } - - internal void HandleException(Exception e, bool completedSynchronously) - { - m_completed = 1; - if (completedSynchronously) - m_completedSynchronously = 1; - else - m_completedSynchronously = 0; - m_exception = e; - - SignalCompletion(); - } - - private void SignalCompletion() - { - if (m_waitHandle != null) m_waitHandle.Set(); - - if (m_callback != null) m_callback(this); - } - - public void EndInvoke() - { - // This method assumes that only 1 thread calls EndInvoke - if (!IsCompleted) - { - // If the operation isn't done, wait for it - AsyncWaitHandle.WaitOne(); - AsyncWaitHandle.Close(); - m_waitHandle.Close(); - m_waitHandle = null; // Allow early GC - } - - // Operation is done: if an exception occured, throw it - if (m_exception != null) throw m_exception; - } - - #endregion - } - - internal class AsyncResult : SimpleAsyncResult - { - private T m_result = default(T); - - public AsyncResult(AsyncCallback asyncCallback, Object state) : - base(asyncCallback, state) - { - } - - public void SetAsCompleted(T result, bool completedSynchronously) - { - // Save the asynchronous operation's result - m_result = result; - - // Tell the base class that the operation completed - // sucessfully (no exception) - base.SetAsCompleted(completedSynchronously); - } - - public new T EndInvoke() - { - base.EndInvoke(); - return m_result; - } - } - -} \ No newline at end of file -- cgit v1.1