diff --git a/OpenSim/Framework/WebUtil.cs b/OpenSim/Framework/WebUtil.cs
index f0817be85e..15f64b8f40 100644
--- a/OpenSim/Framework/WebUtil.cs
+++ b/OpenSim/Framework/WebUtil.cs
@@ -47,6 +47,7 @@ using OpenSim.Framework.ServiceAuth;
using System.Net.Http;
using System.Security.Authentication;
using System.Runtime.CompilerServices;
+using System.Threading;
namespace OpenSim.Framework
{
@@ -358,6 +359,7 @@ namespace OpenSim.Framework
string errorMessage = "unknown error";
int tickstart = Util.EnvironmentTickCount();
+
int sendlen = 0;
int rcvlen = 0;
HttpResponseMessage responseMessage = null;
@@ -1303,11 +1305,13 @@ namespace OpenSim.Framework
///
/// The response. If there was an internal exception, then the default(TResponse) is returned.
///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static TResponse MakeRequest(string verb, string requestUrl, TRequest obj)
{
return MakeRequest(verb, requestUrl, obj, 0, null);
}
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static TResponse MakeRequest(string verb, string requestUrl, TRequest obj, IServiceAuth auth)
{
return MakeRequest(verb, requestUrl, obj, 0, auth);
@@ -1325,6 +1329,7 @@ namespace OpenSim.Framework
/// The response. If there was an internal exception or the request timed out,
/// then the default(TResponse) is returned.
///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static TResponse MakeRequest(string verb, string requestUrl, TRequest obj, int pTimeout)
{
return MakeRequest(verb, requestUrl, obj, pTimeout, null);
@@ -1333,7 +1338,7 @@ namespace OpenSim.Framework
///
/// Perform a synchronous something request.
///
- ///
+ ///
///
///
///
@@ -1343,42 +1348,43 @@ namespace OpenSim.Framework
/// The response. If there was an internal exception or the request timed out,
/// then the default(TResponse) is returned.
///
- public static TResponse MakeRequest(string verb, string requestUrl, TRequest obj, int pTimeout, IServiceAuth auth)
+ public static TResponse MakeRequest(string method, string requestUrl, TRequest obj, int pTimeout, IServiceAuth auth)
{
int reqnum = WebUtil.RequestNumber++;
if (WebUtil.DebugLevel >= 3)
- m_log.Debug($"[LOGHTTP]: HTTP OUT {reqnum} SRestObjReq {verb} {requestUrl}");
-
- int tickstart = Util.EnvironmentTickCount();
+ m_log.Debug($"[LOGHTTP]: HTTP OUT {reqnum} SRestObjReq {method} {requestUrl}");
+ int ticks = Util.EnvironmentTickCount();
TResponse deserial = default;
+ HttpResponseMessage responseMessage = null;
+ HttpRequestMessage request = null;
+ CancellationTokenSource cancellationToken = null;
- HttpWebRequest request;
try
{
- request = (HttpWebRequest)WebRequest.Create(requestUrl);
+ HttpClient client = WebUtil.SharedHttpClientWithRedir;
- if (auth != null)
- auth.AddAuthorization(request.Headers);
+ request = new(new HttpMethod(method), requestUrl);
+
+ auth?.AddAuthorization(request.Headers);
+
+ request.Headers.ExpectContinue = false;
+ request.Headers.TransferEncodingChunked = false;
+
+ //if (keepalive)
+ {
+ request.Headers.TryAddWithoutValidation("Keep-Alive", "timeout=30, max=10");
+ request.Headers.TryAddWithoutValidation("Connection", "Keep-Alive");
+ }
+ //else
+ // request.Headers.TryAddWithoutValidation("Connection", "close");
if (pTimeout != 0)
- request.Timeout = pTimeout;
+ cancellationToken = new CancellationTokenSource(TimeSpan.FromMilliseconds(pTimeout));
- request.Method = verb;
- }
- catch (Exception e)
- {
- m_log.Debug($"[SRestObjReq]: Exception in creating request {verb} {requestUrl}: {e.Message}");
- return deserial;
- }
-
- try
- {
- if ((verb == "POST") || (verb == "PUT"))
+ if (method.Equals("POST",StringComparison.OrdinalIgnoreCase) || method.Equals("PUT", StringComparison.OrdinalIgnoreCase))
{
- request.ContentType = "text/xml";
-
byte[] data;
XmlWriterSettings settings = new() { Encoding = Util.UTF8 };
using (MemoryStream ms = new())
@@ -1391,76 +1397,77 @@ namespace OpenSim.Framework
}
int sendlen = data.Length;
- request.ContentLength = sendlen;
-
if (WebUtil.DebugLevel >= 5)
WebUtil.LogOutgoingDetail("SEND", reqnum, System.Text.Encoding.UTF8.GetString(data));
- using (Stream requestStream = request.GetRequestStream())
- requestStream.Write(data, 0, sendlen);
- data = null;
+ request.Content = new ByteArrayContent(data);
+ request.Content.Headers.TryAddWithoutValidation("Content-Type", "text/xml");
+ request.Content.Headers.TryAddWithoutValidation("Content-Length", sendlen.ToString());
}
- }
- catch (Exception e)
- {
- m_log.Debug( $"[SRestObjReq]: Exception in making request {verb} {requestUrl}: {e.Message}");
- return deserial;
- }
- int rcvlen = 0;
- try
- {
- using HttpWebResponse resp = (HttpWebResponse)request.GetResponse();
- if (resp.ContentLength != 0)
+ if(cancellationToken is null)
+ responseMessage = client.Send(request, HttpCompletionOption.ResponseHeadersRead);
+ else
+ responseMessage = client.Send(request, HttpCompletionOption.ResponseHeadersRead, cancellationToken.Token);
+ responseMessage.EnsureSuccessStatusCode();
+
+ int rcvlen = 0;
+ if ((responseMessage.Content.Headers.ContentLength is long contentLength) && contentLength != 0)
{
- rcvlen = (int)resp.ContentLength;
- using Stream respStream = resp.GetResponseStream();
+ rcvlen = (int)contentLength;
+ using Stream respStream = responseMessage.Content.ReadAsStream();
deserial = XMLResponseHelper.LogAndDeserialize(
- reqnum, respStream, resp.ContentLength);
+ reqnum, respStream, contentLength);
}
else
{
- m_log.Debug($"[SRestObjReq]: Oops! no content found in response stream from {verb} {requestUrl}");
+ m_log.Debug($"[SRestObjReq]: Oops! no content found in response stream from {method} {requestUrl}");
+ }
+
+ ticks = Util.EnvironmentTickCountSubtract(ticks);
+ if (ticks > WebUtil.LongCallTime)
+ {
+ m_log.Info($"[LOGHTTP]: Slow SRestObjReq {reqnum} {method} {requestUrl} took {ticks}ms, {rcvlen}bytes");
+ }
+ else if (WebUtil.DebugLevel >= 4)
+ {
+ m_log.Debug($"[LOGHTTP]: HTTP OUT {reqnum} took {ticks}ms");
}
}
- catch (WebException e)
+ catch (HttpRequestException e)
{
- using HttpWebResponse hwr = (HttpWebResponse)e.Response;
- if (hwr != null)
+ if (e.StatusCode is HttpStatusCode status)
{
- if (hwr.StatusCode == HttpStatusCode.Unauthorized)
+ if (status == HttpStatusCode.Unauthorized)
{
- m_log.Error($"[SRestObjReq]: {requestUrl} requires authentication");
+ m_log.Error($"[SRestObjReq]: GET {requestUrl} requires authentication");
}
- else if (hwr.StatusCode != HttpStatusCode.NotFound)
+ else if (status != HttpStatusCode.NotFound)
{
- m_log.Warn($"[SRestObjReq]: {requestUrl} returned error: {hwr.StatusCode}");
+ m_log.Warn($"[SRestObjReq]: GET {requestUrl} returned error: {status}");
}
}
else
m_log.ErrorFormat(
"[SRestObjReq]: WebException for {0} {1} {2} {3}",
- verb, requestUrl, typeof(TResponse).ToString(), e.Message);
+ method, requestUrl, typeof(TResponse).ToString(), e.Message);
}
catch (System.InvalidOperationException)
{
// This is what happens when there is invalid XML
- m_log.Debug($"[SRestObjReq]: Invalid XML from {verb} {requestUrl} {typeof(TResponse)}");
+ m_log.Debug($"[SRestObjReq]: Invalid XML from {method} {requestUrl} {typeof(TResponse)}");
}
catch (Exception e)
{
- m_log.Debug($"[SRestObjReq]: Exception on response from {verb} {requestUrl}: {e.Message}");
+ m_log.Debug($"[SRestObjReq]: Exception on response from {method} {requestUrl}: {e.Message}");
+ }
+ finally
+ {
+ request?.Dispose();
+ responseMessage?.Dispose();
+ cancellationToken?.Dispose();
}
- int tickdiff = Util.EnvironmentTickCountSubtract(tickstart);
- if (tickdiff > WebUtil.LongCallTime)
- {
- m_log.Info($"[LOGHTTP]: Slow SRestObjReq {reqnum} {verb} {requestUrl} took {tickdiff}ms, {rcvlen}bytes");
- }
- else if (WebUtil.DebugLevel >= 4)
- {
- m_log.Debug($"[LOGHTTP]: HTTP OUT {reqnum} took {tickdiff}ms");
- }
return deserial;
}
@@ -1470,58 +1477,75 @@ namespace OpenSim.Framework
if (WebUtil.DebugLevel >= 3)
m_log.Debug($"[LOGHTTP]: HTTP OUT {reqnum} SRestObjReq GET {requestUrl}");
- int tickstart = Util.EnvironmentTickCount();
+ int ticks = Util.EnvironmentTickCount();
TResponse deserial = default;
- HttpWebRequest request;
+ HttpResponseMessage responseMessage = null;
+ HttpRequestMessage request = null;
+ CancellationTokenSource cancellationToken = null;
try
{
- request = (HttpWebRequest)WebRequest.Create(requestUrl);
+ HttpClient client = WebUtil.SharedHttpClientWithRedir;
- if (auth != null)
- auth.AddAuthorization(request.Headers);
- request.AllowWriteStreamBuffering = false;
+ request = new(HttpMethod.Get, requestUrl);
+
+ auth?.AddAuthorization(request.Headers);
+
+ request.Headers.ExpectContinue = false;
+ request.Headers.TransferEncodingChunked = false;
+
+ //if (keepalive)
+ {
+ request.Headers.TryAddWithoutValidation("Keep-Alive", "timeout=30, max=10");
+ request.Headers.TryAddWithoutValidation("Connection", "Keep-Alive");
+ }
+ //else
+ // request.Headers.TryAddWithoutValidation("Connection", "close");
if (pTimeout != 0)
- request.Timeout = pTimeout;
+ cancellationToken = new CancellationTokenSource(TimeSpan.FromMilliseconds(pTimeout));
- request.Method = "GET";
- }
- catch (Exception e)
- {
- m_log.Debug($"[SRestObjReq]: Exception in creating GET request {requestUrl}: {e.Message}");
- return deserial;
- }
+ if (cancellationToken is null)
+ responseMessage = client.Send(request, HttpCompletionOption.ResponseHeadersRead);
+ else
+ responseMessage = client.Send(request, HttpCompletionOption.ResponseHeadersRead, cancellationToken.Token);
+ responseMessage.EnsureSuccessStatusCode();
- int rcvlen = 0;
- try
- {
- using HttpWebResponse resp = (HttpWebResponse)request.GetResponse();
- if (resp.ContentLength != 0)
+ int rcvlen = 0;
+ if ((responseMessage.Content.Headers.ContentLength is long contentLength) && contentLength != 0)
{
- rcvlen = (int)resp.ContentLength;
- using Stream respStream = resp.GetResponseStream();
+ rcvlen = (int)contentLength;
+ using Stream respStream = responseMessage.Content.ReadAsStream();
deserial = XMLResponseHelper.LogAndDeserialize(
- reqnum, respStream, resp.ContentLength);
+ reqnum, respStream, contentLength);
}
else
{
m_log.Debug($"[SRestObjReq]: Oops! no content found in response stream from GET {requestUrl}");
}
- }
- catch (WebException e)
- {
- using HttpWebResponse hwr = (HttpWebResponse)e.Response;
- if (hwr != null)
+
+ ticks = Util.EnvironmentTickCountSubtract(ticks);
+ if (ticks > WebUtil.LongCallTime)
{
- if (hwr.StatusCode == HttpStatusCode.Unauthorized)
+ m_log.Info($"[LOGHTTP]: Slow SRestObjReq GET {reqnum} {requestUrl} took {ticks}ms, {rcvlen}bytes");
+ }
+ else if (WebUtil.DebugLevel >= 4)
+ {
+ m_log.Debug($"[LOGHTTP]: HTTP OUT {reqnum} took {ticks}ms");
+ }
+ }
+ catch (HttpRequestException e)
+ {
+ if(e.StatusCode is HttpStatusCode status)
+ {
+ if (status == HttpStatusCode.Unauthorized)
{
m_log.Error($"[SRestObjReq]: GET {requestUrl} requires authentication");
}
- else if (hwr.StatusCode != HttpStatusCode.NotFound)
+ else if (status != HttpStatusCode.NotFound)
{
- m_log.Warn($"[SRestObjReq]: GET {requestUrl} returned error: {hwr.StatusCode}");
+ m_log.Warn($"[SRestObjReq]: GET {requestUrl} returned error: {status}");
}
}
else
@@ -1536,15 +1560,11 @@ namespace OpenSim.Framework
{
m_log.Debug($"[SRestObjReq]: Exception on response from GET {requestUrl}: {e.Message}");
}
-
- int tickdiff = Util.EnvironmentTickCountSubtract(tickstart);
- if (tickdiff > WebUtil.LongCallTime)
+ finally
{
- m_log.Info($"[LOGHTTP]: Slow SRestObjReq GET {reqnum} {requestUrl} took {tickdiff}ms, {rcvlen}bytes");
- }
- else if (WebUtil.DebugLevel >= 4)
- {
- m_log.Debug($"[LOGHTTP]: HTTP OUT {reqnum} took {tickdiff}ms");
+ request?.Dispose();
+ responseMessage?.Dispose();
+ cancellationToken?.Dispose();
}
return deserial;
}