Got at least one data fetching method working; turns out, we can't use a patched LogicStack to get the data
This commit is contained in:
87
Vendor/EmbedIO-3.5.2/Internal/BufferingResponseStream.cs
vendored
Normal file
87
Vendor/EmbedIO-3.5.2/Internal/BufferingResponseStream.cs
vendored
Normal file
@@ -0,0 +1,87 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace EmbedIO.Internal
|
||||
{
|
||||
// Wraps a response's output stream, buffering all data
|
||||
// in a MemoryStream.
|
||||
// When disposed, sets the response's ContentLength and copies all data
|
||||
// to the output stream.
|
||||
internal class BufferingResponseStream : Stream
|
||||
{
|
||||
private readonly IHttpResponse _response;
|
||||
private readonly MemoryStream _buffer;
|
||||
|
||||
public BufferingResponseStream(IHttpResponse response)
|
||||
{
|
||||
_response = response;
|
||||
_buffer = new MemoryStream();
|
||||
}
|
||||
|
||||
public override bool CanRead => false;
|
||||
|
||||
public override bool CanSeek => false;
|
||||
|
||||
public override bool CanWrite => true;
|
||||
|
||||
public override long Length => _buffer.Length;
|
||||
|
||||
public override long Position
|
||||
{
|
||||
get => _buffer.Position;
|
||||
set => throw SeekingNotSupported();
|
||||
}
|
||||
|
||||
public override void Flush() => _buffer.Flush();
|
||||
|
||||
public override Task FlushAsync(CancellationToken cancellationToken) => _buffer.FlushAsync(cancellationToken);
|
||||
|
||||
public override int Read(byte[] buffer, int offset, int count) => throw ReadingNotSupported();
|
||||
|
||||
public override int ReadByte() => throw ReadingNotSupported();
|
||||
|
||||
public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
|
||||
=> throw ReadingNotSupported();
|
||||
|
||||
public override int EndRead(IAsyncResult asyncResult) => throw ReadingNotSupported();
|
||||
|
||||
public override Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) => throw ReadingNotSupported();
|
||||
|
||||
public override Task CopyToAsync(Stream destination, int bufferSize, CancellationToken cancellationToken)
|
||||
=> throw ReadingNotSupported();
|
||||
|
||||
public override long Seek(long offset, SeekOrigin origin) => throw SeekingNotSupported();
|
||||
|
||||
public override void SetLength(long value) => throw SeekingNotSupported();
|
||||
|
||||
public override void Write(byte[] buffer, int offset, int count) => _buffer.Write(buffer, offset, count);
|
||||
|
||||
public override void WriteByte(byte value) => _buffer.WriteByte(value);
|
||||
|
||||
public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
|
||||
=> _buffer.BeginWrite(buffer, offset, count, callback, state);
|
||||
|
||||
public override void EndWrite(IAsyncResult asyncResult) => _buffer.EndWrite(asyncResult);
|
||||
|
||||
public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
|
||||
=> _buffer.WriteAsync(buffer, offset, count, cancellationToken);
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
_response.ContentLength64 = _buffer.Length;
|
||||
_buffer.Position = 0;
|
||||
_buffer.CopyTo(_response.OutputStream);
|
||||
|
||||
if (disposing)
|
||||
{
|
||||
_buffer.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
private static Exception ReadingNotSupported() => new NotSupportedException("This stream does not support reading.");
|
||||
|
||||
private static Exception SeekingNotSupported() => new NotSupportedException("This stream does not support seeking.");
|
||||
}
|
||||
}
|
||||
121
Vendor/EmbedIO-3.5.2/Internal/CompressionStream.cs
vendored
Normal file
121
Vendor/EmbedIO-3.5.2/Internal/CompressionStream.cs
vendored
Normal file
@@ -0,0 +1,121 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace EmbedIO.Internal
|
||||
{
|
||||
internal class CompressionStream : Stream
|
||||
{
|
||||
private readonly Stream _target;
|
||||
private readonly bool _leaveOpen;
|
||||
|
||||
public CompressionStream(Stream target, CompressionMethod compressionMethod)
|
||||
{
|
||||
switch (compressionMethod)
|
||||
{
|
||||
case CompressionMethod.Deflate:
|
||||
_target = new DeflateStream(target, CompressionMode.Compress, true);
|
||||
_leaveOpen = false;
|
||||
break;
|
||||
case CompressionMethod.Gzip:
|
||||
_target = new GZipStream(target, CompressionMode.Compress, true);
|
||||
_leaveOpen = false;
|
||||
break;
|
||||
default:
|
||||
_target = target;
|
||||
_leaveOpen = true;
|
||||
break;
|
||||
}
|
||||
|
||||
UncompressedLength = 0;
|
||||
}
|
||||
|
||||
public long UncompressedLength { get; private set; }
|
||||
|
||||
public override bool CanRead => false;
|
||||
|
||||
public override bool CanSeek => false;
|
||||
|
||||
public override bool CanWrite => true;
|
||||
|
||||
public override long Length => throw SeekingNotSupported();
|
||||
|
||||
public override long Position
|
||||
{
|
||||
get => throw SeekingNotSupported();
|
||||
set => throw SeekingNotSupported();
|
||||
}
|
||||
|
||||
public override void Flush() => _target.Flush();
|
||||
|
||||
public override Task FlushAsync(CancellationToken cancellationToken) => _target.FlushAsync(cancellationToken);
|
||||
|
||||
public override int Read(byte[] buffer, int offset, int count) => throw ReadingNotSupported();
|
||||
|
||||
public override int ReadByte() => throw ReadingNotSupported();
|
||||
|
||||
public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
|
||||
=> throw ReadingNotSupported();
|
||||
|
||||
public override int EndRead(IAsyncResult asyncResult) => throw ReadingNotSupported();
|
||||
|
||||
public override Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) => throw ReadingNotSupported();
|
||||
|
||||
public override Task CopyToAsync(Stream destination, int bufferSize, CancellationToken cancellationToken)
|
||||
=> throw ReadingNotSupported();
|
||||
|
||||
public override long Seek(long offset, SeekOrigin origin) => throw SeekingNotSupported();
|
||||
|
||||
public override void SetLength(long value) => throw SeekingNotSupported();
|
||||
|
||||
public override void Write(byte[] buffer, int offset, int count)
|
||||
{
|
||||
_target.Write(buffer, offset, count);
|
||||
UncompressedLength += count;
|
||||
}
|
||||
|
||||
public override void WriteByte(byte value)
|
||||
{
|
||||
_target.WriteByte(value);
|
||||
UncompressedLength++;
|
||||
}
|
||||
|
||||
public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
|
||||
=> _target.BeginWrite(
|
||||
buffer,
|
||||
offset,
|
||||
count,
|
||||
ar => {
|
||||
UncompressedLength += count;
|
||||
callback(ar);
|
||||
},
|
||||
state);
|
||||
|
||||
public override void EndWrite(IAsyncResult asyncResult)
|
||||
{
|
||||
_target.EndWrite(asyncResult);
|
||||
}
|
||||
|
||||
public override async Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
|
||||
{
|
||||
await _target.WriteAsync(buffer, offset, count, cancellationToken).ConfigureAwait(false);
|
||||
UncompressedLength += count;
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && !_leaveOpen)
|
||||
{
|
||||
_target.Dispose();
|
||||
}
|
||||
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
private static Exception ReadingNotSupported() => new NotSupportedException("This stream does not support reading.");
|
||||
|
||||
private static Exception SeekingNotSupported() => new NotSupportedException("This stream does not support seeking.");
|
||||
}
|
||||
}
|
||||
82
Vendor/EmbedIO-3.5.2/Internal/CompressionUtility.cs
vendored
Normal file
82
Vendor/EmbedIO-3.5.2/Internal/CompressionUtility.cs
vendored
Normal file
@@ -0,0 +1,82 @@
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
|
||||
namespace EmbedIO.Internal
|
||||
{
|
||||
internal static class CompressionUtility
|
||||
{
|
||||
public static byte[]? ConvertCompression(byte[] source, CompressionMethod sourceMethod, CompressionMethod targetMethod)
|
||||
{
|
||||
if (source == null)
|
||||
return null;
|
||||
|
||||
if (sourceMethod == targetMethod)
|
||||
return source;
|
||||
|
||||
switch (sourceMethod)
|
||||
{
|
||||
case CompressionMethod.Deflate:
|
||||
using (var sourceStream = new MemoryStream(source, false))
|
||||
{
|
||||
using var decompressionStream = new DeflateStream(sourceStream, CompressionMode.Decompress, true);
|
||||
using var targetStream = new MemoryStream();
|
||||
if (targetMethod == CompressionMethod.Gzip)
|
||||
{
|
||||
using var compressionStream = new GZipStream(targetStream, CompressionMode.Compress, true);
|
||||
decompressionStream.CopyTo(compressionStream);
|
||||
}
|
||||
else
|
||||
{
|
||||
decompressionStream.CopyTo(targetStream);
|
||||
}
|
||||
|
||||
return targetStream.ToArray();
|
||||
}
|
||||
|
||||
case CompressionMethod.Gzip:
|
||||
using (var sourceStream = new MemoryStream(source, false))
|
||||
{
|
||||
using var decompressionStream = new GZipStream(sourceStream, CompressionMode.Decompress, true);
|
||||
using var targetStream = new MemoryStream();
|
||||
if (targetMethod == CompressionMethod.Deflate)
|
||||
{
|
||||
using var compressionStream = new DeflateStream(targetStream, CompressionMode.Compress, true);
|
||||
decompressionStream.CopyToAsync(compressionStream);
|
||||
}
|
||||
else
|
||||
{
|
||||
decompressionStream.CopyTo(targetStream);
|
||||
}
|
||||
|
||||
return targetStream.ToArray();
|
||||
}
|
||||
|
||||
default:
|
||||
using (var sourceStream = new MemoryStream(source, false))
|
||||
{
|
||||
using var targetStream = new MemoryStream();
|
||||
switch (targetMethod)
|
||||
{
|
||||
case CompressionMethod.Deflate:
|
||||
using (var compressionStream = new DeflateStream(targetStream, CompressionMode.Compress, true))
|
||||
sourceStream.CopyTo(compressionStream);
|
||||
|
||||
break;
|
||||
|
||||
case CompressionMethod.Gzip:
|
||||
using (var compressionStream = new GZipStream(targetStream, CompressionMode.Compress, true))
|
||||
sourceStream.CopyTo(compressionStream);
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
// Just in case. Consider all other values as None.
|
||||
return source;
|
||||
}
|
||||
|
||||
return targetStream.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
27
Vendor/EmbedIO-3.5.2/Internal/DummyWebModuleContainer.cs
vendored
Normal file
27
Vendor/EmbedIO-3.5.2/Internal/DummyWebModuleContainer.cs
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
using System.Collections.Concurrent;
|
||||
using System.Runtime.CompilerServices;
|
||||
using EmbedIO.Utilities;
|
||||
using Swan;
|
||||
|
||||
namespace EmbedIO.Internal
|
||||
{
|
||||
internal sealed class DummyWebModuleContainer : IWebModuleContainer
|
||||
{
|
||||
public static readonly IWebModuleContainer Instance = new DummyWebModuleContainer();
|
||||
|
||||
private DummyWebModuleContainer()
|
||||
{
|
||||
}
|
||||
|
||||
public IComponentCollection<IWebModule> Modules => throw UnexpectedCall();
|
||||
|
||||
public ConcurrentDictionary<object, object> SharedItems => throw UnexpectedCall();
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
}
|
||||
|
||||
private InternalErrorException UnexpectedCall([CallerMemberName] string member = "")
|
||||
=> SelfCheck.Failure($"Unexpected call to {nameof(DummyWebModuleContainer)}.{member}.");
|
||||
}
|
||||
}
|
||||
9
Vendor/EmbedIO-3.5.2/Internal/LockableNameValueCollection.cs
vendored
Normal file
9
Vendor/EmbedIO-3.5.2/Internal/LockableNameValueCollection.cs
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
using System.Collections.Specialized;
|
||||
|
||||
namespace EmbedIO.Internal
|
||||
{
|
||||
internal sealed class LockableNameValueCollection : NameValueCollection
|
||||
{
|
||||
public void MakeReadOnly() => IsReadOnly = true;
|
||||
}
|
||||
}
|
||||
63
Vendor/EmbedIO-3.5.2/Internal/MimeTypeCustomizer.cs
vendored
Normal file
63
Vendor/EmbedIO-3.5.2/Internal/MimeTypeCustomizer.cs
vendored
Normal file
@@ -0,0 +1,63 @@
|
||||
using System.Collections.Generic;
|
||||
using EmbedIO.Utilities;
|
||||
using Swan.Configuration;
|
||||
|
||||
namespace EmbedIO.Internal
|
||||
{
|
||||
internal sealed class MimeTypeCustomizer : ConfiguredObject, IMimeTypeCustomizer
|
||||
{
|
||||
private readonly Dictionary<string, string> _customMimeTypes = new Dictionary<string, string>();
|
||||
private readonly Dictionary<(string, string), bool> _data = new Dictionary<(string, string), bool>();
|
||||
|
||||
private bool? _defaultPreferCompression;
|
||||
|
||||
public string GetMimeType(string extension)
|
||||
{
|
||||
_customMimeTypes.TryGetValue(Validate.NotNull(nameof(extension), extension), out var result);
|
||||
return result;
|
||||
}
|
||||
|
||||
public bool TryDetermineCompression(string mimeType, out bool preferCompression)
|
||||
{
|
||||
var (type, subtype) = MimeType.UnsafeSplit(
|
||||
Validate.MimeType(nameof(mimeType), mimeType, false));
|
||||
|
||||
if (_data.TryGetValue((type, subtype), out preferCompression))
|
||||
return true;
|
||||
|
||||
if (_data.TryGetValue((type, "*"), out preferCompression))
|
||||
return true;
|
||||
|
||||
if (!_defaultPreferCompression.HasValue)
|
||||
return false;
|
||||
|
||||
preferCompression = _defaultPreferCompression.Value;
|
||||
return true;
|
||||
}
|
||||
|
||||
public void AddCustomMimeType(string extension, string mimeType)
|
||||
{
|
||||
EnsureConfigurationNotLocked();
|
||||
_customMimeTypes[Validate.NotNullOrEmpty(nameof(extension), extension)]
|
||||
= Validate.MimeType(nameof(mimeType), mimeType, false);
|
||||
}
|
||||
|
||||
public void PreferCompression(string mimeType, bool preferCompression)
|
||||
{
|
||||
EnsureConfigurationNotLocked();
|
||||
var (type, subtype) = MimeType.UnsafeSplit(
|
||||
Validate.MimeType(nameof(mimeType), mimeType, true));
|
||||
|
||||
if (type == "*")
|
||||
{
|
||||
_defaultPreferCompression = preferCompression;
|
||||
}
|
||||
else
|
||||
{
|
||||
_data[(type, subtype)] = preferCompression;
|
||||
}
|
||||
}
|
||||
|
||||
public void Lock() => LockConfiguration();
|
||||
}
|
||||
}
|
||||
15
Vendor/EmbedIO-3.5.2/Internal/RequestHandlerPassThroughException.cs
vendored
Normal file
15
Vendor/EmbedIO-3.5.2/Internal/RequestHandlerPassThroughException.cs
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
using System;
|
||||
|
||||
namespace EmbedIO.Internal
|
||||
{
|
||||
// This exception is only created and handled internally,
|
||||
// so it doesn't need all the standard the bells and whistles.
|
||||
#pragma warning disable CA1032 // Add standard exception constructors
|
||||
#pragma warning disable CA1064 // Exceptions should be public
|
||||
|
||||
internal class RequestHandlerPassThroughException : Exception
|
||||
{
|
||||
}
|
||||
#pragma warning restore CA1032
|
||||
#pragma warning restore CA1064
|
||||
}
|
||||
27
Vendor/EmbedIO-3.5.2/Internal/TimeKeeper.cs
vendored
Normal file
27
Vendor/EmbedIO-3.5.2/Internal/TimeKeeper.cs
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace EmbedIO.Internal
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a wrapper around Stopwatch.
|
||||
/// </summary>
|
||||
public sealed class TimeKeeper
|
||||
{
|
||||
private static readonly Stopwatch Stopwatch = Stopwatch.StartNew();
|
||||
|
||||
private readonly long _start;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="TimeKeeper"/> class.
|
||||
/// </summary>
|
||||
public TimeKeeper()
|
||||
{
|
||||
_start = Stopwatch.ElapsedMilliseconds;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the elapsed time since the class was initialized.
|
||||
/// </summary>
|
||||
public long ElapsedTime => Stopwatch.ElapsedMilliseconds - _start;
|
||||
}
|
||||
}
|
||||
47
Vendor/EmbedIO-3.5.2/Internal/UriUtility.cs
vendored
Normal file
47
Vendor/EmbedIO-3.5.2/Internal/UriUtility.cs
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
using System;
|
||||
|
||||
namespace EmbedIO.Internal
|
||||
{
|
||||
internal static class UriUtility
|
||||
{
|
||||
public static Uri StringToUri(string str)
|
||||
{
|
||||
_ = Uri.TryCreate(str, CanBeAbsoluteUrl(str) ? UriKind.Absolute : UriKind.Relative, out var result);
|
||||
return result;
|
||||
}
|
||||
|
||||
public static Uri? StringToAbsoluteUri(string str)
|
||||
{
|
||||
if (!CanBeAbsoluteUrl(str))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
_ = Uri.TryCreate(str, UriKind.Absolute, out var result);
|
||||
return result;
|
||||
}
|
||||
|
||||
// Returns true if string starts with "http:", "https:", "ws:", or "wss:"
|
||||
private static bool CanBeAbsoluteUrl(string str)
|
||||
=> !string.IsNullOrEmpty(str)
|
||||
&& str[0] switch {
|
||||
'h' => str.Length >= 5
|
||||
&& str[1] == 't'
|
||||
&& str[2] == 't'
|
||||
&& str[3] == 'p'
|
||||
&& str[4] switch {
|
||||
':' => true,
|
||||
's' => str.Length >= 6 && str[5] == ':',
|
||||
_ => false
|
||||
},
|
||||
'w' => str.Length >= 3
|
||||
&& str[1] == 's'
|
||||
&& str[2] switch {
|
||||
':' => true,
|
||||
's' => str.Length >= 4 && str[3] == ':',
|
||||
_ => false
|
||||
},
|
||||
_ => false
|
||||
};
|
||||
}
|
||||
}
|
||||
46
Vendor/EmbedIO-3.5.2/Internal/WebModuleCollection.cs
vendored
Normal file
46
Vendor/EmbedIO-3.5.2/Internal/WebModuleCollection.cs
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using EmbedIO.Utilities;
|
||||
using Swan.Logging;
|
||||
|
||||
namespace EmbedIO.Internal
|
||||
{
|
||||
internal sealed class WebModuleCollection : DisposableComponentCollection<IWebModule>
|
||||
{
|
||||
private readonly string _logSource;
|
||||
|
||||
internal WebModuleCollection(string logSource)
|
||||
{
|
||||
_logSource = logSource;
|
||||
}
|
||||
|
||||
internal void StartAll(CancellationToken cancellationToken)
|
||||
{
|
||||
foreach (var (name, module) in WithSafeNames)
|
||||
{
|
||||
$"Starting module {name}...".Debug(_logSource);
|
||||
module.Start(cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
internal async Task DispatchRequestAsync(IHttpContext context)
|
||||
{
|
||||
if (context.IsHandled)
|
||||
return;
|
||||
|
||||
var requestedPath = context.RequestedPath;
|
||||
foreach (var (name, module) in WithSafeNames)
|
||||
{
|
||||
var routeMatch = module.MatchUrlPath(requestedPath);
|
||||
if (routeMatch == null)
|
||||
continue;
|
||||
|
||||
$"[{context.Id}] Processing with {name}.".Debug(_logSource);
|
||||
context.GetImplementation().Route = routeMatch;
|
||||
await module.HandleRequestAsync(context).ConfigureAwait(false);
|
||||
if (context.IsHandled)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user