From 03e0ec8fd75abc466bb13dc346f4ee3bbad88018 Mon Sep 17 00:00:00 2001 From: Cinder Date: Fri, 6 May 2022 18:25:02 -0500 Subject: [PATCH] Flesh out more of HttpCapsClient --- LibreMetaverse/Capabilities/HttpCapsClient.cs | 223 +++++++++++------- 1 file changed, 141 insertions(+), 82 deletions(-) diff --git a/LibreMetaverse/Capabilities/HttpCapsClient.cs b/LibreMetaverse/Capabilities/HttpCapsClient.cs index 34875278..d2a6dd0f 100644 --- a/LibreMetaverse/Capabilities/HttpCapsClient.cs +++ b/LibreMetaverse/Capabilities/HttpCapsClient.cs @@ -27,8 +27,12 @@ using System; using System.IO; using System.Net.Http; +using System.Net.Http.Headers; using System.Threading; using System.Threading.Tasks; +using OpenMetaverse.Interfaces; +using OpenMetaverse.Rendering; +using OpenMetaverse.StructuredData; namespace LibreMetaverse { @@ -43,24 +47,124 @@ namespace LibreMetaverse #region GET requests - public async Task GetRequestAsync(Uri uri, DownloadCompleteHandler completeHandler, DownloadProgressHandler progressHandler) + public async Task GetRequestAsync(Uri uri, DownloadCompleteHandler completeHandler, + DownloadProgressHandler progressHandler, CancellationToken? cancellationToken) { - - using var response = await GetAsync(uri, HttpCompletionOption.ResponseHeadersRead); - if (!response.IsSuccessStatusCode) - { - completeHandler?.Invoke(response, null, - new HttpRequestException(response.StatusCode + " " + response.ReasonPhrase)); - } - - await ProcessResponseAsync(response, completeHandler, progressHandler); + using var request = new HttpRequestMessage(HttpMethod.Get, uri); + await SendRequestAsync(request, completeHandler, progressHandler, cancellationToken); } - public async Task GetRequestAsync(Uri uri, DownloadCompleteHandler completeHandler, - DownloadProgressHandler progressHandler, CancellationToken cancellationToken) + #endregion GET requests + + #region POST requests + + public async Task PostRequestAsync(Uri uri, string contentType, byte[] payload, + DownloadCompleteHandler completeHandler, DownloadProgressHandler progressHandler, + CancellationToken? cancellationToken) { - - using var response = await GetAsync(uri, HttpCompletionOption.ResponseHeadersRead, cancellationToken); + using var request = new HttpRequestMessage(HttpMethod.Post, uri); + request.Content = new ByteArrayContent(payload); + request.Content.Headers.ContentType = new MediaTypeHeaderValue(contentType); + await SendRequestAsync(request, completeHandler, progressHandler, cancellationToken); + } + + public async Task PostRequestAsync(Uri uri, OSDFormat format, OSD payload, + DownloadCompleteHandler completeHandler, DownloadProgressHandler progressHandler, + CancellationToken? cancellationToken) + { + SerializeData(format, payload, out var serialized, out var contentType); + using var request = new HttpRequestMessage(HttpMethod.Post, uri); + request.Content = new ByteArrayContent(serialized); + request.Content.Headers.ContentType = contentType; + await SendRequestAsync(request, completeHandler, progressHandler, cancellationToken); + } + + #endregion POST requests + + #region PUT requests + + public async Task PutRequestAsync(Uri uri, string contentType, byte[] payload, + DownloadCompleteHandler completeHandler, DownloadProgressHandler progressHandler, + CancellationToken? cancellationToken) + { + using var request = new HttpRequestMessage(HttpMethod.Put, uri); + request.Content = new ByteArrayContent(payload); + request.Content.Headers.ContentType = new MediaTypeHeaderValue(contentType); + await SendRequestAsync(request, completeHandler, progressHandler, cancellationToken); + } + + public async Task PutRequestAsync(Uri uri, OSDFormat format, OSD payload, + DownloadCompleteHandler completeHandler, DownloadProgressHandler progressHandler, + CancellationToken? cancellationToken) + { + SerializeData(format, payload, out var serialized, out var contentType); + using var request = new HttpRequestMessage(HttpMethod.Put, uri); + request.Content = new ByteArrayContent(serialized); + request.Content.Headers.ContentType = contentType; + await SendRequestAsync(request, completeHandler, progressHandler, cancellationToken); + } + + #endregion PUT requests + + #region PATCH requests + + public async Task PatchRequestAsync(Uri uri, string contentType, byte[] payload, + DownloadCompleteHandler completeHandler, DownloadProgressHandler progressHandler, + CancellationToken? cancellationToken) + { + using var request = new HttpRequestMessage(HttpMethod.Patch, uri); + request.Content = new ByteArrayContent(payload); + request.Content.Headers.ContentType = new MediaTypeHeaderValue(contentType); + await SendRequestAsync(request, completeHandler, progressHandler, cancellationToken); + } + + public async Task PatchRequestAsync(Uri uri, OSDFormat format, OSD payload, + DownloadCompleteHandler completeHandler, DownloadProgressHandler progressHandler, + CancellationToken? cancellationToken) + { + SerializeData(format, payload, out var serialized, out var contentType); + using var request = new HttpRequestMessage(HttpMethod.Patch, uri); + request.Content = new ByteArrayContent(serialized); + request.Content.Headers.ContentType = contentType; + await SendRequestAsync(request, completeHandler, progressHandler, cancellationToken); + } + + #endregion PATCH requests + + #region DELETE requests + + public async Task DeleteRequestAsync(Uri uri, string contentType, byte[] payload, + DownloadCompleteHandler completeHandler, DownloadProgressHandler progressHandler, + CancellationToken? cancellationToken) + { + using var request = new HttpRequestMessage(HttpMethod.Delete, uri); + request.Content = new ByteArrayContent(payload); + request.Content.Headers.ContentType = new MediaTypeHeaderValue(contentType); + await SendRequestAsync(request, completeHandler, progressHandler, cancellationToken); + } + + public async Task DeleteRequestAsync(Uri uri, OSDFormat format, OSD payload, + DownloadCompleteHandler completeHandler, DownloadProgressHandler progressHandler, + CancellationToken? cancellationToken) + { + SerializeData(format, payload, out var serialized, out var contentType); + using var request = new HttpRequestMessage(HttpMethod.Delete, uri); + request.Content = new ByteArrayContent(serialized); + request.Content.Headers.ContentType = contentType; + await SendRequestAsync(request, completeHandler, progressHandler, cancellationToken); + } + + #endregion DELETE requests + + /// /// /// /// /// /// /// /// /// /// /// /// + + private async Task SendRequestAsync(HttpRequestMessage request, + DownloadCompleteHandler completeHandler, DownloadProgressHandler progressHandler, + CancellationToken? cancellationToken) + { + using var response = (cancellationToken.HasValue) + ? await SendAsync(request, HttpCompletionOption.ResponseHeadersRead, cancellationToken.Value) + : await SendAsync(request, HttpCompletionOption.ResponseHeadersRead); if (!response.IsSuccessStatusCode) { completeHandler?.Invoke(response, null, @@ -70,13 +174,9 @@ namespace LibreMetaverse await ProcessResponseAsync(response, completeHandler, progressHandler, cancellationToken); } - #endregion GET requests - - - /// /// /// /// /// /// /// /// /// /// /// /// - - private static async Task ProcessResponseAsync(HttpResponseMessage response, - DownloadCompleteHandler completeHandler, DownloadProgressHandler progressHandler) + private static async Task ProcessResponseAsync(HttpResponseMessage response, + DownloadCompleteHandler completeHandler, DownloadProgressHandler progressHandler, + CancellationToken? cancellationToken) { var totalBytes = response.Content.Headers.ContentLength; await using var contentStream = await response.Content.ReadAsStreamAsync(); @@ -84,7 +184,7 @@ namespace LibreMetaverse var length = (int)(totalBytes ?? 8192); var totalSize = totalBytes ?? 0; var ms = totalBytes.HasValue ? null : new MemoryStream(); - byte[] buffer = new byte[length]; + var buffer = new byte[length]; byte[] responseData = null; Exception error = null; var bytesRead = 0; @@ -93,8 +193,9 @@ namespace LibreMetaverse try { - while (contentStream != null - && (bytesRead = await contentStream.ReadAsync(buffer, offset, buffer.Length)) != 0) + while (contentStream != null /* (╯°□°)╯︵ ┻━┻ */ + && ((!cancellationToken.HasValue && (bytesRead = await contentStream.ReadAsync(buffer, offset, buffer.Length)) != 0) + || (cancellationToken.HasValue && (bytesRead = await contentStream.ReadAsync(buffer, offset, buffer.Length, cancellationToken.Value)) != 0))) { totalBytesRead += bytesRead; @@ -138,67 +239,25 @@ namespace LibreMetaverse completeHandler?.Invoke(response, responseData, error); } - private static async Task ProcessResponseAsync(HttpResponseMessage response, - DownloadCompleteHandler completeHandler, DownloadProgressHandler progressHandler, CancellationToken cancellationToken) + private static void SerializeData(OSDFormat format, OSD data, + out byte[] serializedData, out MediaTypeHeaderValue contentType) { - var totalBytes = response.Content.Headers.ContentLength; - await using var contentStream = await response.Content.ReadAsStreamAsync(); - - var length = (int)(totalBytes ?? 8192); - var totalSize = totalBytes ?? 0; - var ms = totalBytes.HasValue ? null : new MemoryStream(); - byte[] buffer = new byte[length]; - byte[] responseData = null; - Exception error = null; - var bytesRead = 0; - var offset = 0; - var totalBytesRead = 0; - - try + switch (format) { - while (contentStream != null - && (bytesRead = await contentStream.ReadAsync(buffer, offset, buffer.Length, cancellationToken)) != 0) - { - totalBytesRead += bytesRead; - - if (totalBytes.HasValue) - { - offset += bytesRead; - length -= bytesRead; - } - else - { - totalSize += (length - bytesRead); - ms.Write(buffer, 0, bytesRead); - } - - double? progressPercent = null; - if (totalBytes.HasValue) - { - progressPercent = Math.Round((double)totalBytesRead / totalBytes.Value * 100, 2); - } - - progressHandler?.Invoke(totalBytes, totalBytesRead, progressPercent); - - } - - if (totalBytes.HasValue) - { - responseData = buffer; - } - else - { - responseData = ms.ToArray(); - ms.Close(); - await ms.DisposeAsync(); - } + case OSDFormat.Xml: + serializedData = OSDParser.SerializeLLSDXmlBytes(data); + contentType = new MediaTypeHeaderValue("application/llsd+xml"); + break; + case OSDFormat.Binary: + serializedData = OSDParser.SerializeLLSDBinary(data); + contentType = new MediaTypeHeaderValue("application/llsd+binary"); + break; + case OSDFormat.Json: + default: + serializedData = System.Text.Encoding.UTF8.GetBytes(OSDParser.SerializeJsonString(data)); + contentType = new MediaTypeHeaderValue("application/llsd+json"); + break; } - catch (Exception ex) - { - error = ex; - } - - completeHandler?.Invoke(response, responseData, error); } } }