aboutsummaryrefslogtreecommitdiff
path: root/lib/Net.Http/src
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Net.Http/src')
-rw-r--r--lib/Net.Http/src/Core/Compression/IHttpCompressorManager.cs7
-rw-r--r--lib/Net.Http/src/Core/Compression/IResponseCompressor.cs10
-rw-r--r--lib/Net.Http/src/Core/Compression/ManagedHttpCompressor.cs34
-rw-r--r--lib/Net.Http/src/Core/Response/ResponseWriter.cs40
-rw-r--r--lib/Net.Http/src/IMemoryResponseReader.cs (renamed from lib/Net.Http/src/IMemoryResponseEntity.cs)6
5 files changed, 71 insertions, 26 deletions
diff --git a/lib/Net.Http/src/Core/Compression/IHttpCompressorManager.cs b/lib/Net.Http/src/Core/Compression/IHttpCompressorManager.cs
index 982fa28..80763f8 100644
--- a/lib/Net.Http/src/Core/Compression/IHttpCompressorManager.cs
+++ b/lib/Net.Http/src/Core/Compression/IHttpCompressorManager.cs
@@ -72,6 +72,13 @@ namespace VNLib.Net.Http
ReadOnlyMemory<byte> CompressBlock(object compressorState, ReadOnlyMemory<byte> input, bool finalBlock);
/// <summary>
+ /// Flushes any stored compressor data that still needs to be sent to the client.
+ /// </summary>
+ /// <param name="compressorState">The compressor state instance</param>
+ /// <returns>The remaining data stored in the compressor state, may be empty if no data is pending</returns>
+ ReadOnlyMemory<byte> Flush(object compressorState);
+
+ /// <summary>
/// Initializes the compressor state for a compression operation
/// </summary>
/// <param name="compressorState">The user-defined compression state</param>
diff --git a/lib/Net.Http/src/Core/Compression/IResponseCompressor.cs b/lib/Net.Http/src/Core/Compression/IResponseCompressor.cs
index 0beea28..a68a838 100644
--- a/lib/Net.Http/src/Core/Compression/IResponseCompressor.cs
+++ b/lib/Net.Http/src/Core/Compression/IResponseCompressor.cs
@@ -50,10 +50,16 @@ namespace VNLib.Net.Http.Core.Compression
/// </summary>
/// <param name="compMethod">The compression mode to use</param>
/// <param name="output">The stream to write compressed data to</param>
- void Init(Stream output, CompressionMethod compMethod);
+ void Init(Stream output, CompressionMethod compMethod);
/// <summary>
- /// Compresses a block of data and writes it to the output stream
+ /// Gets a value that indicates if the compressor requires more flushing to occur
+ /// </summary>
+ bool IsFlushRequired();
+
+ /// <summary>
+ /// Compresses a block of data and writes it to the output stream. If an empty flush is
+ /// commited, then the input buffer will be empty.
/// </summary>
/// <param name="buffer">The block of memory to write to compress</param>
/// <param name="finalBlock">A value that indicates if this block is the final block</param>
diff --git a/lib/Net.Http/src/Core/Compression/ManagedHttpCompressor.cs b/lib/Net.Http/src/Core/Compression/ManagedHttpCompressor.cs
index e580b2d..b3f971a 100644
--- a/lib/Net.Http/src/Core/Compression/ManagedHttpCompressor.cs
+++ b/lib/Net.Http/src/Core/Compression/ManagedHttpCompressor.cs
@@ -29,7 +29,6 @@ using System.Threading.Tasks;
namespace VNLib.Net.Http.Core.Compression
{
-
internal sealed class ManagedHttpCompressor : IResponseCompressor
{
//Store the compressor
@@ -49,13 +48,31 @@ namespace VNLib.Net.Http.Core.Compression
private object? _compressor;
private Stream? _stream;
+ private ReadOnlyMemory<byte> _lastFlush;
+ private bool initialized;
///<inheritdoc/>
public int BlockSize { get; private set; }
+ public bool IsFlushRequired()
+ {
+ //See if a flush is required
+ _lastFlush = _provider.Flush(_compressor!);
+ return _lastFlush.Length > 0;
+ }
+
///<inheritdoc/>
public ValueTask CompressBlockAsync(ReadOnlyMemory<byte> buffer, bool finalBlock)
{
+ /*
+ * If input buffer is empty and flush data is available,
+ * write the last flush data to the stream
+ */
+ if(buffer.Length == 0 && _lastFlush.Length > 0)
+ {
+ return _stream!.WriteAsync(_lastFlush);
+ }
+
//Compress the block
ReadOnlyMemory<byte> result = _provider.CompressBlock(_compressor!, buffer, finalBlock);
@@ -68,7 +85,14 @@ namespace VNLib.Net.Http.Core.Compression
{
//Remove stream ref and de-init the compressor
_stream = null;
- _provider.DeinitCompressor(_compressor!);
+ _lastFlush = default;
+
+ //Deinit compressor if initialized
+ if (initialized)
+ {
+ _provider.DeinitCompressor(_compressor!);
+ initialized = false;
+ }
}
///<inheritdoc/>
@@ -76,10 +100,12 @@ namespace VNLib.Net.Http.Core.Compression
{
//Defer alloc the compressor
_compressor ??= _provider.AllocCompressor();
+
+ //Init the compressor and get the block size
+ BlockSize = _provider.InitCompressor(_compressor, compMethod);
- //Store the stream and init the compressor
_stream = output;
- BlockSize = _provider.InitCompressor(_compressor, compMethod);
+ initialized = true;
}
}
} \ No newline at end of file
diff --git a/lib/Net.Http/src/Core/Response/ResponseWriter.cs b/lib/Net.Http/src/Core/Response/ResponseWriter.cs
index 7a448a1..77dc619 100644
--- a/lib/Net.Http/src/Core/Response/ResponseWriter.cs
+++ b/lib/Net.Http/src/Core/Response/ResponseWriter.cs
@@ -91,11 +91,12 @@ namespace VNLib.Net.Http.Core
#pragma warning disable CA2007 // Consider calling ConfigureAwait on the awaited task
+ ReadOnlyMemory<byte> _readSegment;
+
///<inheritdoc/>
async Task IHttpResponseBody.WriteEntityAsync(Stream dest, long count, Memory<byte> buffer)
{
int remaining;
- ReadOnlyMemory<byte> segment;
//Write a sliding window response
if (_memoryResponse != null)
@@ -107,16 +108,16 @@ namespace VNLib.Net.Http.Core
while (remaining > 0)
{
//Get remaining segment
- segment = _memoryResponse.GetRemainingConstrained(remaining);
+ _readSegment = _memoryResponse.GetRemainingConstrained(remaining);
//Write segment to output stream
- await dest.WriteAsync(segment);
+ await dest.WriteAsync(_readSegment);
//Advance by the written ammount
- _memoryResponse.Advance(segment.Length);
+ _memoryResponse.Advance(_readSegment.Length);
//Update remaining
- remaining -= segment.Length;
+ remaining -= _readSegment.Length;
}
}
else
@@ -135,8 +136,6 @@ namespace VNLib.Net.Http.Core
///<inheritdoc/>
async Task IHttpResponseBody.WriteEntityAsync(Stream dest, Memory<byte> buffer)
{
- ReadOnlyMemory<byte> segment;
-
//Write a sliding window response
if (_memoryResponse != null)
{
@@ -144,13 +143,13 @@ namespace VNLib.Net.Http.Core
while (_memoryResponse.Remaining > 0)
{
//Get remaining segment
- segment = _memoryResponse.GetMemory();
+ _readSegment = _memoryResponse.GetMemory();
//Write segment to output stream
- await dest.WriteAsync(segment);
+ await dest.WriteAsync(_readSegment);
//Advance by the written ammount
- _memoryResponse.Advance(segment.Length);
+ _memoryResponse.Advance(_readSegment.Length);
}
}
else
@@ -172,7 +171,6 @@ namespace VNLib.Net.Http.Core
//Locals
bool remaining;
int read;
- ReadOnlyMemory<byte> segment;
//Write a sliding window response
if (_memoryResponse != null)
@@ -197,16 +195,16 @@ namespace VNLib.Net.Http.Core
//Write response body from memory
do
{
- segment = _memoryResponse.GetRemainingConstrained(dest.BlockSize);
+ _readSegment = _memoryResponse.GetRemainingConstrained(dest.BlockSize);
//Advance by the trimmed segment length
- _memoryResponse.Advance(segment.Length);
+ _memoryResponse.Advance(_readSegment.Length);
//Check if data is remaining after an advance
remaining = _memoryResponse.Remaining > 0;
//Compress the trimmed block
- await dest.CompressBlockAsync(segment, !remaining);
+ await dest.CompressBlockAsync(_readSegment, !remaining);
} while (remaining);
}
@@ -214,16 +212,16 @@ namespace VNLib.Net.Http.Core
{
do
{
- segment = _memoryResponse.GetMemory();
+ _readSegment = _memoryResponse.GetMemory();
//Advance by the segment length, this should be safe even if its zero
- _memoryResponse.Advance(segment.Length);
+ _memoryResponse.Advance(_readSegment.Length);
//Check if data is remaining after an advance
remaining = _memoryResponse.Remaining > 0;
//Write to output
- await dest.CompressBlockAsync(segment, !remaining);
+ await dest.CompressBlockAsync(_readSegment, !remaining);
} while (remaining);
}
@@ -264,6 +262,13 @@ namespace VNLib.Net.Http.Core
//remove ref so its not disposed again
_streamResponse = null;
}
+
+ //Continue flusing flushing the compressor if required
+ while(dest.IsFlushRequired())
+ {
+ //Flush the compressor
+ await dest.CompressBlockAsync(ReadOnlyMemory<byte>.Empty, true);
+ }
}
#pragma warning restore CA2007 // Consider calling ConfigureAwait on the awaited task
@@ -274,6 +279,7 @@ namespace VNLib.Net.Http.Core
//Clear has data flag
HasData = false;
Length = 0;
+ _readSegment = default;
//Clear rseponse containers
_streamResponse?.Dispose();
diff --git a/lib/Net.Http/src/IMemoryResponseEntity.cs b/lib/Net.Http/src/IMemoryResponseReader.cs
index aa77f58..a54cec7 100644
--- a/lib/Net.Http/src/IMemoryResponseEntity.cs
+++ b/lib/Net.Http/src/IMemoryResponseReader.cs
@@ -1,11 +1,11 @@
/*
-* Copyright (c) 2022 Vaughn Nugent
+* Copyright (c) 2023 Vaughn Nugent
*
* Library: VNLib
* Package: VNLib.Net.Http
-* File: IMemoryResponseEntity.cs
+* File: IMemoryResponseReader.cs
*
-* IMemoryResponseEntity.cs is part of VNLib.Net.Http which is part of the larger
+* IMemoryResponseReader.cs is part of VNLib.Net.Http which is part of the larger
* VNLib collection of libraries and utilities.
*
* VNLib.Net.Http is free software: you can redistribute it and/or modify