Fix bug where outstanding llHTTPRequests for scripts were not being aborted when they were deleted.

This was because AsyncCommandManager was handing an item ID to IHttpRequestModule.StopHttpRequest() rather than the expected request ID.
This commit also makes the http request asynchronous using BeginGetResponse() rather than doing this by launching a new thread
so that we can more safely abort it via HttpWebRequest.Abort() rather than aborting the thread itself.
This also renames StopHttpRequest() to StopHttpRequestsForScript() since any outstanding requests are now aborted and/or removed.
user_profiles
Justin Clark-Casey (justincc) 2013-04-04 00:36:15 +01:00
parent 94d44142e3
commit 831e4c3850
3 changed files with 77 additions and 33 deletions

View File

@ -28,12 +28,15 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq;
using System.Net; using System.Net;
using System.Net.Mail; using System.Net.Mail;
using System.Net.Security; using System.Net.Security;
using System.Reflection;
using System.Text; using System.Text;
using System.Threading; using System.Threading;
using System.Security.Cryptography.X509Certificates; using System.Security.Cryptography.X509Certificates;
using log4net;
using Nini.Config; using Nini.Config;
using OpenMetaverse; using OpenMetaverse;
using OpenSim.Framework; using OpenSim.Framework;
@ -250,19 +253,30 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest
return reqID; return reqID;
} }
public void StopHttpRequest(uint m_localID, UUID m_itemID) public void StopHttpRequestsForScript(UUID id)
{ {
if (m_pendingRequests != null) if (m_pendingRequests != null)
{ {
List<UUID> keysToRemove = null;
lock (HttpListLock) lock (HttpListLock)
{ {
HttpRequestClass tmpReq; foreach (HttpRequestClass req in m_pendingRequests.Values)
if (m_pendingRequests.TryGetValue(m_itemID, out tmpReq))
{ {
tmpReq.Stop(); if (req.ItemID == id)
m_pendingRequests.Remove(m_itemID); {
req.Stop();
if (keysToRemove == null)
keysToRemove = new List<UUID>();
keysToRemove.Add(req.ReqID);
} }
} }
if (keysToRemove != null)
keysToRemove.ForEach(keyToRemove => m_pendingRequests.Remove(keyToRemove));
}
} }
} }
@ -362,6 +376,8 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest
public class HttpRequestClass: IServiceRequest public class HttpRequestClass: IServiceRequest
{ {
// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
// Constants for parameters // Constants for parameters
// public const int HTTP_BODY_MAXLENGTH = 2; // public const int HTTP_BODY_MAXLENGTH = 2;
// public const int HTTP_METHOD = 0; // public const int HTTP_METHOD = 0;
@ -419,12 +435,7 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest
public void Process() public void Process()
{ {
httpThread = new Thread(SendRequest); SendRequest();
httpThread.Name = "HttpRequestThread";
httpThread.Priority = ThreadPriority.BelowNormal;
httpThread.IsBackground = true;
_finished = false;
httpThread.Start();
} }
/* /*
@ -435,10 +446,6 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest
public void SendRequest() public void SendRequest()
{ {
HttpWebResponse response = null; HttpWebResponse response = null;
StringBuilder sb = new StringBuilder();
byte[] buf = new byte[8192];
string tempString = null;
int count = 0;
try try
{ {
@ -497,11 +504,12 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest
bstream.Close(); bstream.Close();
} }
Request.Timeout = HttpTimeout;
try try
{ {
// execute the request IAsyncResult result = (IAsyncResult)Request.BeginGetResponse(ResponseCallback, null);
response = (HttpWebResponse) Request.GetResponse();
ThreadPool.RegisterWaitForSingleObject(
result.AsyncWaitHandle, new WaitOrTimerCallback(TimeoutCallback), null, HttpTimeout, true);
} }
catch (WebException e) catch (WebException e)
{ {
@ -510,11 +518,31 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest
throw; throw;
} }
response = (HttpWebResponse)e.Response; response = (HttpWebResponse)e.Response;
_finished = true;
}
}
catch (Exception e)
{
Status = (int)OSHttpStatusCode.ClientErrorJoker;
ResponseBody = e.Message;
_finished = true;
}
} }
private void ResponseCallback(IAsyncResult ar)
{
HttpWebResponse response = null;
try
{
response = (HttpWebResponse)Request.EndGetResponse(ar);
Status = (int)response.StatusCode; Status = (int)response.StatusCode;
Stream resStream = response.GetResponseStream(); Stream resStream = response.GetResponseStream();
StringBuilder sb = new StringBuilder();
byte[] buf = new byte[8192];
string tempString = null;
int count = 0;
do do
{ {
@ -530,7 +558,8 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest
// continue building the string // continue building the string
sb.Append(tempString); sb.Append(tempString);
} }
} while (count > 0); // any more data to read? }
while (count > 0); // any more data to read?
ResponseBody = sb.ToString(); ResponseBody = sb.ToString();
} }
@ -539,27 +568,30 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest
Status = (int)OSHttpStatusCode.ClientErrorJoker; Status = (int)OSHttpStatusCode.ClientErrorJoker;
ResponseBody = e.Message; ResponseBody = e.Message;
_finished = true; // m_log.Debug(
return; // string.Format("[SCRIPTS HTTP REQUESTS]: Exception on response to {0} for {1} ", Url, ItemID), e);
} }
finally finally
{ {
if (response != null) if (response != null)
response.Close(); response.Close();
}
_finished = true; _finished = true;
} }
}
private void TimeoutCallback(object state, bool timedOut)
{
if (timedOut)
Request.Abort();
}
public void Stop() public void Stop()
{ {
try // m_log.DebugFormat("[SCRIPTS HTTP REQUESTS]: Stopping request to {0} for {1} ", Url, ItemID);
{
httpThread.Abort(); if (Request != null)
} Request.Abort();
catch (Exception)
{
}
} }
} }
} }

View File

@ -45,7 +45,13 @@ namespace OpenSim.Region.Framework.Interfaces
{ {
UUID MakeHttpRequest(string url, string parameters, string body); UUID MakeHttpRequest(string url, string parameters, string body);
UUID StartHttpRequest(uint localID, UUID itemID, string url, List<string> parameters, Dictionary<string, string> headers, string body); UUID StartHttpRequest(uint localID, UUID itemID, string url, List<string> parameters, Dictionary<string, string> headers, string body);
void StopHttpRequest(uint m_localID, UUID m_itemID);
/// <summary>
/// Stop and remove all http requests for the given script.
/// </summary>
/// <param name='id'></param>
void StopHttpRequestsForScript(UUID id);
IServiceRequest GetNextCompletedRequest(); IServiceRequest GetNextCompletedRequest();
void RemoveCompletedRequest(UUID id); void RemoveCompletedRequest(UUID id);
} }

View File

@ -28,7 +28,9 @@
using System; using System;
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Reflection;
using System.Threading; using System.Threading;
using log4net;
using OpenMetaverse; using OpenMetaverse;
using OpenSim.Framework; using OpenSim.Framework;
using OpenSim.Framework.Monitoring; using OpenSim.Framework.Monitoring;
@ -45,6 +47,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
/// </summary> /// </summary>
public class AsyncCommandManager public class AsyncCommandManager
{ {
// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private static Thread cmdHandlerThread; private static Thread cmdHandlerThread;
private static int cmdHandlerThreadCycleSleepms; private static int cmdHandlerThreadCycleSleepms;
@ -225,6 +229,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
/// <param name="itemID"></param> /// <param name="itemID"></param>
public static void RemoveScript(IScriptEngine engine, uint localID, UUID itemID) public static void RemoveScript(IScriptEngine engine, uint localID, UUID itemID)
{ {
// m_log.DebugFormat("[ASYNC COMMAND MANAGER]: Removing facilities for script {0}", itemID);
// Remove a specific script // Remove a specific script
// Remove dataserver events // Remove dataserver events
@ -236,7 +242,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
// Remove from: HttpRequest // Remove from: HttpRequest
IHttpRequestModule iHttpReq = engine.World.RequestModuleInterface<IHttpRequestModule>(); IHttpRequestModule iHttpReq = engine.World.RequestModuleInterface<IHttpRequestModule>();
if (iHttpReq != null) if (iHttpReq != null)
iHttpReq.StopHttpRequest(localID, itemID); iHttpReq.StopHttpRequestsForScript(itemID);
IWorldComm comms = engine.World.RequestModuleInterface<IWorldComm>(); IWorldComm comms = engine.World.RequestModuleInterface<IWorldComm>();
if (comms != null) if (comms != null)