diff --git a/Ooui.Forms/Forms.cs b/Ooui.Forms/Forms.cs index 7e87aa3..8c06773 100644 --- a/Ooui.Forms/Forms.cs +++ b/Ooui.Forms/Forms.cs @@ -1,6 +1,4 @@ using System; -using System.Diagnostics; -using Xamarin.Forms; using Xamarin.Forms.Internals; using Ooui.Forms; using System.IO; @@ -8,6 +6,7 @@ using System.Reflection; using System.Threading; using System.Threading.Tasks; using Ooui; +using System.Net.Http; namespace Xamarin.Forms { @@ -37,6 +36,9 @@ namespace Xamarin.Forms public static event EventHandler ViewInitialized; + public static HttpClientHandler HttpClientHandler { get; set; } + + public static void SendViewInitialized (this VisualElement self, Ooui.Element nativeView) { ViewInitialized?.Invoke (self, new ViewInitializedEventArgs { View = self, NativeView = nativeView }); @@ -69,7 +71,7 @@ namespace Xamarin.Forms public string GetMD5Hash (string input) { - throw new NotImplementedException (); + return Utilities.GetMd5Hash(input); } public double GetNamedSize (NamedSize size, Type targetElementType, bool useOldSizes) @@ -89,9 +91,30 @@ namespace Xamarin.Forms } } - public Task GetStreamAsync (Uri uri, CancellationToken cancellationToken) + + public async Task GetStreamAsync (Uri uri, CancellationToken cancellationToken) { - throw new NotImplementedException (); + //NOTE: Wanted to use the same facility that ImageLoaderSourceHandler uses, + // but couldn't find an optional way to ignore certificate errors with self-signed + // certificates with that approach. Calling: + // ServicePointManager.ServerCertificateValidationCallback += (o, cert, chain, errors) => true; + // in web application seemed to get ignored. + + //var imageSource = new UriImageSource() { Uri = uri }; + //return imageSource.GetStreamAsync(cancellationToken); + + using (var client = HttpClientHandler == null ? new HttpClient() : new HttpClient(HttpClientHandler)) + { + HttpResponseMessage streamResponse = await client.GetAsync(uri.AbsoluteUri).ConfigureAwait(false); + + if (!streamResponse.IsSuccessStatusCode) + { + Log.Warning("HTTP Request", $"Could not retrieve {uri}, status code {streamResponse.StatusCode}"); + return null; + } + + return await streamResponse.Content.ReadAsStreamAsync().ConfigureAwait(false); + } } public IIsolatedStorageFile GetUserStoreForApplication () diff --git a/Ooui.Forms/Renderers/ImageRenderer.cs b/Ooui.Forms/Renderers/ImageRenderer.cs index 591dea7..a58b53a 100644 --- a/Ooui.Forms/Renderers/ImageRenderer.cs +++ b/Ooui.Forms/Renderers/ImageRenderer.cs @@ -213,7 +213,7 @@ namespace Ooui.Forms.Renderers using (var outputStream = new System.IO.MemoryStream (data)) { await streamImage.CopyToAsync (outputStream, 4096, cancelationToken).ConfigureAwait (false); } - var hash = Ooui.Utilities.Hash (data); + var hash = Ooui.Utilities.GetShaHash (data); var etag = "\"" + hash + "\""; image = "/images/" + hash; if (Ooui.UI.TryGetFileContentAtPath (image, out var file) && file.Etag == etag) { diff --git a/Ooui/UI.cs b/Ooui/UI.cs index 50bf1a8..51a5842 100644 --- a/Ooui/UI.cs +++ b/Ooui/UI.cs @@ -85,7 +85,7 @@ namespace Ooui clientJsBytes = Encoding.UTF8.GetBytes (r.ReadToEnd ()); } } - clientJsEtag = "\"" + Utilities.Hash (clientJsBytes) + "\""; + clientJsEtag = "\"" + Utilities.GetShaHash (clientJsBytes) + "\""; } static void Publish (string path, RequestHandler handler) @@ -117,13 +117,13 @@ namespace Ooui if (contentType == null) { contentType = GuessContentType (path, filePath); } - var etag = "\"" + Utilities.Hash (data) + "\""; + var etag = "\"" + Utilities.GetShaHash (data) + "\""; Publish (path, new DataHandler (data, etag, contentType)); } public static void PublishFile (string path, byte[] data, string contentType) { - var etag = "\"" + Utilities.Hash (data) + "\""; + var etag = "\"" + Utilities.GetShaHash (data) + "\""; Publish (path, new DataHandler (data, etag, contentType)); } @@ -168,7 +168,7 @@ namespace Ooui public static void PublishJson (string path, object value) { var data = JsonHandler.GetData (value); - var etag = "\"" + Utilities.Hash (data) + "\""; + var etag = "\"" + Utilities.GetShaHash (data) + "\""; Publish (path, new DataHandler (data, etag, JsonHandler.ContentType)); } diff --git a/Ooui/Utilities.cs b/Ooui/Utilities.cs index af30793..8665b75 100644 --- a/Ooui/Utilities.cs +++ b/Ooui/Utilities.cs @@ -1,4 +1,5 @@ using System; +using System.Security.Cryptography; using System.Text; namespace Ooui @@ -6,21 +7,54 @@ namespace Ooui public static class Utilities { [ThreadStatic] - static System.Security.Cryptography.SHA256 sha256; + static SHA256 sha256; - public static string Hash (byte[] bytes) + [ThreadStatic] + static MD5 md5; + + public static string GetShaHash(byte[] bytes) { var sha = sha256; - if (sha == null) { - sha = System.Security.Cryptography.SHA256.Create (); + if (sha == null) + { + sha = SHA256.Create(); sha256 = sha; } - var data = sha.ComputeHash (bytes); - StringBuilder sBuilder = new StringBuilder (); - for (int i = 0; i < data.Length; i++) { - sBuilder.Append (data[i].ToString ("x2")); + var data = sha.ComputeHash(bytes); + + return BytesToString(data); + } + + public static string GetMd5Hash(string input) + { + var md = md5; + if (md == null) + { + md = MD5.Create(); + md5 = md; } - return sBuilder.ToString (); + + // Convert the input string to a byte array and compute the hash. + byte[] data = md.ComputeHash(Encoding.UTF8.GetBytes(input)); + + return BytesToString(data); + } + + private static string BytesToString(byte[] data) + { + // Create a new Stringbuilder to collect the bytes + // and create a string. + StringBuilder sBuilder = new StringBuilder(); + + // Loop through each byte of the hashed data + // and format each one as a hexadecimal string. + for (int i = 0; i < data.Length; i++) + { + sBuilder.Append(data[i].ToString("x2")); + } + + // Return the hexadecimal string. + return sBuilder.ToString(); } } }