aboutsummaryrefslogtreecommitdiff
path: root/lib/Net.Http
diff options
context:
space:
mode:
authorLibravatar vnugent <public@vaughnnugent.com>2024-03-31 17:00:45 -0400
committerLibravatar vnugent <public@vaughnnugent.com>2024-03-31 17:00:45 -0400
commit21130c889bd8564b201aa16c8f645abdf85d374a (patch)
tree57e685f0f7e5c341264eb890112de35206f3d289 /lib/Net.Http
parent55859158fbd0bf54473a0baeb486045a025c7c5d (diff)
Squashed commit of the following:
commit 448a93bb1d18d032087afe2476ffccb98634a54c Author: vnugent <public@vaughnnugent.com> Date: Sun Mar 31 16:56:51 2024 -0400 ci: fix third-party dir cleanup commit 9afed1427472da1ea13079f98dbe27339e55ee7d Author: vnugent <public@vaughnnugent.com> Date: Sun Mar 31 16:43:15 2024 -0400 perf: Deprecate unsafememoryhandle span extensions commit 3ff90da4f02af47ea6d233fdd4445337ebe36452 Author: vnugent <public@vaughnnugent.com> Date: Sat Mar 30 21:36:18 2024 -0400 refactor: Updates, advanced tracing, http optimizations commit 8d6b79b5ae309b36f265ba81529bcef8bfcd7414 Merge: 6c1667b 5585915 Author: vnugent <public@vaughnnugent.com> Date: Sun Mar 24 21:01:31 2024 -0400 Merge branch 'main' into develop commit 6c1667be23597513537f8190e2f55d65eb9b7c7a Author: vnugent <public@vaughnnugent.com> Date: Fri Mar 22 12:01:53 2024 -0400 refactor: Overhauled native library loading and lazy init commit ebf688f2f974295beabf7b5def7e6f6f150551d0 Author: vnugent <public@vaughnnugent.com> Date: Wed Mar 20 22:16:17 2024 -0400 refactor: Update compression header files and macros + Ci build commit 9c7b564911080ccd5cbbb9851a0757b05e1e9047 Author: vnugent <public@vaughnnugent.com> Date: Tue Mar 19 21:54:49 2024 -0400 refactor: JWK overhaul & add length getter to FileUpload commit 6d8c3444e09561e5957491b3cc1ae858e0abdd14 Author: vnugent <public@vaughnnugent.com> Date: Mon Mar 18 16:13:20 2024 -0400 feat: Add FNV1a software checksum and basic correction tests commit 00d182088cecefc08ca80b1faee9bed3f215f40b Author: vnugent <public@vaughnnugent.com> Date: Fri Mar 15 01:05:27 2024 -0400 chore: #6 Use utils filewatcher instead of built-in commit d513c10d9895c6693519ef1d459c6a5a76929436 Author: vnugent <public@vaughnnugent.com> Date: Sun Mar 10 21:58:14 2024 -0400 source tree project location updated
Diffstat (limited to 'lib/Net.Http')
-rw-r--r--lib/Net.Http/src/Core/HttpContext.cs6
-rw-r--r--lib/Net.Http/src/Core/HttpEvent.cs15
-rw-r--r--lib/Net.Http/src/Core/HttpServerProcessing.cs47
-rw-r--r--lib/Net.Http/src/Core/IHttpLifeCycle.cs7
-rw-r--r--lib/Net.Http/src/Core/InitDataBuffer.cs36
-rw-r--r--lib/Net.Http/src/Core/Request/HttpInputStream.cs81
-rw-r--r--lib/Net.Http/src/Core/Request/HttpRequest.cs3
-rw-r--r--lib/Net.Http/src/Core/Request/HttpRequestBody.cs70
-rw-r--r--lib/Net.Http/src/Core/Request/HttpRequestExtensions.cs71
-rw-r--r--lib/Net.Http/src/Core/RequestParse/Http11ParseExtensions.cs12
-rw-r--r--lib/Net.Http/src/Core/Response/HttpResponse.cs18
-rw-r--r--lib/Net.Http/src/Core/Response/HttpStreamResponse.cs7
-rw-r--r--lib/Net.Http/src/Core/Response/HttpstreamResponse.cs7
-rw-r--r--lib/Net.Http/src/Helpers/HttpRange.cs9
-rw-r--r--lib/Net.Http/src/HttpBufferConfig.cs8
15 files changed, 194 insertions, 203 deletions
diff --git a/lib/Net.Http/src/Core/HttpContext.cs b/lib/Net.Http/src/Core/HttpContext.cs
index 8cecf30..f742e97 100644
--- a/lib/Net.Http/src/Core/HttpContext.cs
+++ b/lib/Net.Http/src/Core/HttpContext.cs
@@ -96,7 +96,7 @@ namespace VNLib.Net.Http.Core
*/
if (supportedMethods != CompressionMethod.None)
{
- Debug.Assert(server.Config.CompressorManager != null, "Expected non-null provider");
+ Debug.Assert(server.Config.CompressorManager != null, "Expected non-null compressor manager");
_compressor = new ManagedHttpCompressor(server.Config.CompressorManager);
}
else
@@ -153,7 +153,7 @@ namespace VNLib.Net.Http.Core
Buffers.AllocateBuffer(ParentServer.Config.MemoryPool);
//Init new connection
- Response.OnNewConnection();
+ Response.OnNewConnection(ctx.ConnectionStream);
}
///<inheritdoc/>
@@ -199,7 +199,7 @@ namespace VNLib.Net.Http.Core
Response.OnRelease();
//Free buffers
- Buffers.FreeAll(true);
+ Buffers.FreeAll(ParentServer.Config.BufferConfig.ZeroBuffersOnDisconnect);
return true;
}
diff --git a/lib/Net.Http/src/Core/HttpEvent.cs b/lib/Net.Http/src/Core/HttpEvent.cs
index 8867a12..37c5ab5 100644
--- a/lib/Net.Http/src/Core/HttpEvent.cs
+++ b/lib/Net.Http/src/Core/HttpEvent.cs
@@ -33,18 +33,11 @@ using VNLib.Net.Http.Core.Response;
namespace VNLib.Net.Http
{
- internal sealed class HttpEvent : MarshalByRefObject, IHttpEvent
+ internal sealed class HttpEvent(HttpContext ctx) : MarshalByRefObject, IHttpEvent
{
- private HttpContext Context;
- private ConnectionInfo _ci;
- private FileUpload[] _uploads;
-
- internal HttpEvent(HttpContext ctx)
- {
- Context = ctx;
- _ci = new ConnectionInfo(ctx);
- _uploads = ctx.Request.CopyUploads();
- }
+ private HttpContext Context = ctx;
+ private ConnectionInfo _ci = new(ctx);
+ private FileUpload[] _uploads = ctx.Request.CopyUploads();
///<inheritdoc/>
IConnectionInfo IHttpEvent.Server => _ci;
diff --git a/lib/Net.Http/src/Core/HttpServerProcessing.cs b/lib/Net.Http/src/Core/HttpServerProcessing.cs
index 8a9ca07..7770ad7 100644
--- a/lib/Net.Http/src/Core/HttpServerProcessing.cs
+++ b/lib/Net.Http/src/Core/HttpServerProcessing.cs
@@ -181,8 +181,16 @@ namespace VNLib.Net.Http
return false;
}
+ bool keepalive = true;
+
+ //Handle an error parsing the request
+ if(!PreProcessRequest(context, (HttpStatusCode)status, ref keepalive))
+ {
+ return false;
+ }
+
//process the request
- bool keepalive = await ProcessRequestAsync(context, (HttpStatusCode)status);
+ bool processSuccess = await ProcessRequestAsync(context);
#if DEBUG
static void WriteConnectionDebugLog(HttpServer server, HttpContext context)
@@ -210,18 +218,17 @@ namespace VNLib.Net.Http
WriteConnectionDebugLog(this, context);
}
#endif
-
- //Close the response
+
await context.WriteResponseAsync();
-
- //Flush the stream before returning
+
await context.FlushTransportAsync();
/*
* If an alternate protocol was specified, we need to break the keepalive loop
+ * the handler will manage the alternate protocol
*/
- return keepalive & context.AlternateProtocol == null;
+ return processSuccess & keepalive & context.AlternateProtocol == null;
}
finally
{
@@ -259,8 +266,7 @@ namespace VNLib.Net.Http
//Get the parse buffer
IHttpHeaderParseBuffer parseBuffer = ctx.Buffers.RequestHeaderParseBuffer;
-
- //Init parser
+
TransportReader reader = new (ctx.GetTransport(), parseBuffer, _config.HttpEncoding, HeaderLineTermination);
HttpStatusCode code;
@@ -278,13 +284,13 @@ namespace VNLib.Net.Http
}
//Parse the headers
- if ((code = ctx.Request.Http1ParseHeaders(ref parseState, ref reader, Config, lineBuf)) > 0)
+ if ((code = ctx.Request.Http1ParseHeaders(ref parseState, ref reader, in _config, lineBuf)) > 0)
{
return code;
}
//Prepare entity body for request
- if ((code = ctx.Request.Http1PrepareEntityBody(ref parseState, ref reader, Config)) > 0)
+ if ((code = ctx.Request.Http1PrepareEntityBody(ref parseState, ref reader, in _config)) > 0)
{
return code;
}
@@ -303,8 +309,7 @@ namespace VNLib.Net.Http
}
}
- [MethodImpl(MethodImplOptions.AggressiveOptimization)]
- private async Task<bool> ProcessRequestAsync(HttpContext context, HttpStatusCode status)
+ private bool PreProcessRequest(HttpContext context, HttpStatusCode status, ref bool keepalive)
{
//Check status
if (status != 0)
@@ -340,12 +345,12 @@ namespace VNLib.Net.Http
context.Respond(HttpStatusCode.ServiceUnavailable);
return false;
}
-
+
//Store keepalive value from request, and check if keepalives are enabled by the configuration
- bool keepalive = context.Request.State.KeepAlive & _config.ConnectionKeepAlive > TimeSpan.Zero;
-
+ keepalive = context.Request.State.KeepAlive & _config.ConnectionKeepAlive > TimeSpan.Zero;
+
//Set connection header (only for http1.1)
-
+
if (keepalive)
{
/*
@@ -363,6 +368,12 @@ namespace VNLib.Net.Http
context.Response.Headers.Set(HttpResponseHeader.Connection, "closed");
}
+ return true;
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveOptimization)]
+ private async Task<bool> ProcessRequestAsync(HttpContext context)
+ {
//Get the server root for the specified location or fallback to a wildcard host if one is selected
IWebRoot? root = ServerRoots!.GetValueOrDefault(context.Request.State.Location.DnsSafeHost, _wildcardRoot);
@@ -370,7 +381,7 @@ namespace VNLib.Net.Http
{
context.Respond(HttpStatusCode.NotFound);
//make sure control leaves
- return keepalive;
+ return true;
}
//Check the expect header and return an early status code
@@ -449,7 +460,7 @@ namespace VNLib.Net.Http
*
* For now I will allow it.
*/
- return keepalive;
+ return true;
}
}
diff --git a/lib/Net.Http/src/Core/IHttpLifeCycle.cs b/lib/Net.Http/src/Core/IHttpLifeCycle.cs
index 9ba5ff1..12a1f3f 100644
--- a/lib/Net.Http/src/Core/IHttpLifeCycle.cs
+++ b/lib/Net.Http/src/Core/IHttpLifeCycle.cs
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2023 Vaughn Nugent
+* Copyright (c) 2024 Vaughn Nugent
*
* Library: VNLib
* Package: VNLib.Net.Http
@@ -58,10 +58,5 @@ namespace VNLib.Net.Http.Core
/// method should not throw exceptions
/// </remarks>
void OnComplete();
-
- /// <summary>
- /// Raised when a new connection is established on the current context
- /// </summary>
- void OnNewConnection();
}
} \ No newline at end of file
diff --git a/lib/Net.Http/src/Core/InitDataBuffer.cs b/lib/Net.Http/src/Core/InitDataBuffer.cs
index 6a400bb..6d559cd 100644
--- a/lib/Net.Http/src/Core/InitDataBuffer.cs
+++ b/lib/Net.Http/src/Core/InitDataBuffer.cs
@@ -24,11 +24,13 @@
using System;
using System.Buffers;
+using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using VNLib.Utils;
using VNLib.Utils.Extensions;
+using VNLib.Utils.Memory;
namespace VNLib.Net.Http.Core
{
@@ -84,6 +86,14 @@ namespace VNLib.Net.Http.Core
set => MemoryMarshal.Write(_positionSegment, in value);
}
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private readonly int GetDataPosition()
+ {
+ Debug.Assert(Position >= 0 && Position <= _dataSize, "Invalid position value");
+ //Points to the first byte of the data segment to read from
+ return POSITION_SEG_SIZE + Position;
+ }
+
/// <summary>
/// Get the amount of data remaining in the data buffer
/// </summary>
@@ -94,6 +104,19 @@ namespace VNLib.Net.Http.Core
}
/// <summary>
+ /// Performs a discard in a single operation by setting the
+ /// position to the end of the data buffer
+ /// </summary>
+ /// <returns>The number of bytes that were remaining in the buffer before the discard</returns>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal readonly int DiscardRemaining()
+ {
+ int remaining = Remaining;
+ Position = _dataSize;
+ return remaining;
+ }
+
+ /// <summary>
/// Reads data from the internal buffer into the supplied buffer
/// </summary>
/// <param name="buffer">The buffer to write data to</param>
@@ -103,11 +126,14 @@ namespace VNLib.Net.Http.Core
{
//Calc how many bytes can be read into the output buffer
int bytesToRead = Math.Min(Remaining, buffer.Length);
-
- Span<byte> btr = DataSegment.Slice(Position, bytesToRead);
-
- //Write data to output buffer
- btr.CopyTo(buffer);
+
+ MemoryUtil.Memmove(
+ ref MemoryMarshal.GetArrayDataReference(_buffer),
+ (nuint)GetDataPosition(),
+ ref MemoryMarshal.GetReference(buffer),
+ 0,
+ (nuint)bytesToRead
+ );
//Update position pointer
Position += bytesToRead;
diff --git a/lib/Net.Http/src/Core/Request/HttpInputStream.cs b/lib/Net.Http/src/Core/Request/HttpInputStream.cs
index e36d1e4..ccaa336 100644
--- a/lib/Net.Http/src/Core/Request/HttpInputStream.cs
+++ b/lib/Net.Http/src/Core/Request/HttpInputStream.cs
@@ -40,14 +40,18 @@ namespace VNLib.Net.Http.Core
/// </summary>
internal sealed class HttpInputStream(IHttpContextInformation ContextInfo) : Stream
{
-
- private long ContentLength;
- private Stream? InputStream;
- private long _position;
-
+ private StreamState _state;
private InitDataBuffer? _initalData;
- private long Remaining => Math.Max(ContentLength - _position, 0);
+ private long Remaining
+ {
+ get
+ {
+ long remaining = _state.ContentLength - _state.Position;
+ Debug.Assert(remaining >= 0, "Input stream overrun. Read more data than was available for the connection");
+ return remaining;
+ }
+ }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void OnComplete()
@@ -59,12 +63,7 @@ namespace VNLib.Net.Http.Core
_initalData = null;
}
- //Remove stream cache copy
- InputStream = null;
- //Reset position
- _position = 0;
- //reset content length
- ContentLength = 0;
+ _state = default;
}
/// <summary>
@@ -74,9 +73,8 @@ namespace VNLib.Net.Http.Core
/// <param name="contentLength">The number of bytes to allow being read from the transport or initial buffer</param>
internal ref InitDataBuffer? Prepare(long contentLength)
{
- ContentLength = contentLength;
- //Cache transport stream
- InputStream = ContextInfo.GetTransport();
+ _state.ContentLength = contentLength;
+ _state.InputStream = ContextInfo.GetTransport();
return ref _initalData;
}
@@ -105,13 +103,13 @@ namespace VNLib.Net.Http.Core
/// <summary>
/// Gets the total size of the entity body (aka Content-Length)
/// </summary>
- public override long Length => ContentLength;
+ public override long Length => _state.ContentLength;
/// <summary>
/// Gets the number of bytes currently read from the entity body, setting the
/// position is a NOOP
/// </summary>
- public override long Position { get => _position; set { } }
+ public override long Position { get => _state.Position; set { } }
/// <summary>
/// NOOP
@@ -149,19 +147,19 @@ namespace VNLib.Net.Http.Core
writer.Advance(read);
//Update position
- _position += read;
+ _state.Position += read;
}
//See if data is still remaining to be read from transport (reamining size is also the amount of data that can be read)
if (writer.RemainingSize > 0)
{
//Read from transport
- ERRNO read = InputStream!.Read(writer.Remaining);
+ ERRNO read = _state.InputStream!.Read(writer.Remaining);
//Update writer position
writer.Advance(read);
- _position += read;
+ _state.Position += read;
}
//Return number of bytes written to the buffer
@@ -196,19 +194,19 @@ namespace VNLib.Net.Http.Core
writer.Advance(read);
//Update position
- _position += read;
+ _state.Position += read;
}
//See if data is still remaining to be read from transport (reamining size is also the amount of data that can be read)
if (writer.RemainingSize > 0)
{
//Read from transport
- int read = await InputStream!.ReadAsync(writer.Remaining, cancellationToken).ConfigureAwait(true);
+ int read = await _state.InputStream!.ReadAsync(writer.Remaining, cancellationToken).ConfigureAwait(true);
//Update writer position
writer.Advance(read);
- _position += read;
+ _state.Position += read;
}
//Return number of bytes written to the buffer
@@ -232,7 +230,7 @@ namespace VNLib.Net.Http.Core
if(_initalData.HasValue && remaining <= _initalData.Value.Remaining)
{
//All data has been buffred, so just clear the buffer
- _position = Length;
+ _state.Position = Length;
return ValueTask.CompletedTask;
}
//We must actaully disacrd data from the stream
@@ -244,14 +242,31 @@ namespace VNLib.Net.Http.Core
private async ValueTask DiscardStreamDataAsync()
{
- int read;
- do
+ DiscardInternalBuffer();
+
+ int read, bytesToRead = (int)Math.Min(HttpServer.WriteOnlyScratchBuffer.Length, Remaining);
+
+ while (bytesToRead > 0)
{
//Read data to the discard buffer until reading is completed (read == 0)
- read = await ReadAsync(HttpServer.WriteOnlyScratchBuffer, CancellationToken.None)
+ read = await _state.InputStream!.ReadAsync(HttpServer.WriteOnlyScratchBuffer.Slice(0, bytesToRead), CancellationToken.None)
.ConfigureAwait(true);
- } while (read > 0);
+ //Update position
+ _state.Position += read;
+
+ //Recalculate the number of bytes to read
+ bytesToRead = (int)Math.Min(HttpServer.WriteOnlyScratchBuffer.Length, Remaining);
+ }
+ }
+
+ private void DiscardInternalBuffer()
+ {
+ if (_initalData.HasValue)
+ {
+ //Update the stream position with remaining data
+ _state.Position += _initalData.Value.DiscardRemaining();
+ }
}
/// <summary>
@@ -260,12 +275,20 @@ namespace VNLib.Net.Http.Core
/// <param name="offset"></param>
/// <param name="origin"></param>
/// <returns></returns>
- public override long Seek(long offset, SeekOrigin origin) => _position;
+ public override long Seek(long offset, SeekOrigin origin) => _state.Position;
///<inheritdoc/>
public override void SetLength(long value) => throw new NotSupportedException();
///<inheritdoc/>
public override void Write(byte[] buffer, int offset, int count) => throw new NotSupportedException();
+
+
+ private struct StreamState
+ {
+ public Stream? InputStream;
+ public long Position;
+ public long ContentLength;
+ }
}
} \ No newline at end of file
diff --git a/lib/Net.Http/src/Core/Request/HttpRequest.cs b/lib/Net.Http/src/Core/Request/HttpRequest.cs
index ce8257f..3ebf0d4 100644
--- a/lib/Net.Http/src/Core/Request/HttpRequest.cs
+++ b/lib/Net.Http/src/Core/Request/HttpRequest.cs
@@ -81,9 +81,6 @@ namespace VNLib.Net.Http.Core
void IHttpLifeCycle.OnRelease()
{ }
-
- void IHttpLifeCycle.OnNewConnection()
- { }
void IHttpLifeCycle.OnNewRequest()
{ }
diff --git a/lib/Net.Http/src/Core/Request/HttpRequestBody.cs b/lib/Net.Http/src/Core/Request/HttpRequestBody.cs
deleted file mode 100644
index e39a35c..0000000
--- a/lib/Net.Http/src/Core/Request/HttpRequestBody.cs
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
-* Copyright (c) 2023 Vaughn Nugent
-*
-* Library: VNLib
-* Package: VNLib.Net.Http
-* File: HttpRequestBody.cs
-*
-* HttpRequestBody.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
-* it under the terms of the GNU Affero General Public License as
-* published by the Free Software Foundation, either version 3 of the
-* License, or (at your option) any later version.
-*
-* VNLib.Net.Http is distributed in the hope that it will be useful,
-* but WITHOUT ANY WARRANTY; without even the implied warranty of
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-* GNU Affero General Public License for more details.
-*
-* You should have received a copy of the GNU Affero General Public License
-* along with this program. If not, see https://www.gnu.org/licenses/.
-*/
-
-using System;
-using System.Collections.Generic;
-
-namespace VNLib.Net.Http.Core
-{
- /// <summary>
- /// Represents a higher-level request entity body (query arguments, request body etc)
- /// that has been parsed and captured
- /// </summary>
- internal class HttpRequestBody
- {
- public readonly List<FileUpload> Uploads;
- public readonly Dictionary<string, string> RequestArgs;
- public readonly Dictionary<string, string> QueryArgs;
-
- public HttpRequestBody()
- {
- Uploads = new(1);
-
- //Request/query args should not be case sensitive
- RequestArgs = new(StringComparer.OrdinalIgnoreCase);
- QueryArgs = new(StringComparer.OrdinalIgnoreCase);
- }
-
- /// <summary>
- /// Releases all resources used by the current instance
- /// </summary>
- public void OnComplete()
- {
- //Only enumerate/clear if file uplaods are present
- if (Uploads.Count > 0)
- {
- //Dispose all initialized files
- for (int i = 0; i < Uploads.Count; i++)
- {
- Uploads[i].Free();
- }
- //Emtpy list
- Uploads.Clear();
- }
- //Clear request args and file uplaods
- RequestArgs.Clear();
- QueryArgs.Clear();
- }
- }
-} \ No newline at end of file
diff --git a/lib/Net.Http/src/Core/Request/HttpRequestExtensions.cs b/lib/Net.Http/src/Core/Request/HttpRequestExtensions.cs
index 69bd2af..878622e 100644
--- a/lib/Net.Http/src/Core/Request/HttpRequestExtensions.cs
+++ b/lib/Net.Http/src/Core/Request/HttpRequestExtensions.cs
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2023 Vaughn Nugent
+* Copyright (c) 2024 Vaughn Nugent
*
* Library: VNLib
* Package: VNLib.Net.Http
@@ -91,9 +91,17 @@ namespace VNLib.Net.Http.Core
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool IsCrossOrigin(this HttpRequest Request)
{
- return Request.State.Origin != null
- && (!Request.State.Origin.Authority.Equals(Request.State.Location.Authority, StringComparison.Ordinal)
- || !Request.State.Origin.Scheme.Equals(Request.State.Location.Scheme, StringComparison.Ordinal));
+ if(Request.State.Origin is null)
+ {
+ return false;
+ }
+
+ //Get the origin string components for comparison (allocs new strings :( )
+ string locOrigin = Request.State.Location.GetComponents(UriComponents.SchemeAndServer, UriFormat.SafeUnescaped);
+ string reqOrigin = Request.State.Origin.GetComponents(UriComponents.SchemeAndServer, UriFormat.SafeUnescaped);
+
+ //If origin components are not equal, this is a cross origin request
+ return !string.Equals(locOrigin, reqOrigin, StringComparison.OrdinalIgnoreCase);
}
/// <summary>
@@ -136,18 +144,6 @@ namespace VNLib.Net.Http.Core
{
HttpRequest request = context.Request;
IHttpContextInformation info = context;
- IHttpMemoryPool pool = context.ParentServer.Config.MemoryPool;
-
- //Gets the max form data buffer size to help calculate the initial char buffer size
- int maxBufferSize = context.ParentServer.Config.BufferConfig.FormDataBufferSize;
-
- //Calculate a largest available buffer to read the entire stream or up to the maximum buffer size
- int bufferSize = (int)Math.Min(request.InputStream.Length, maxBufferSize);
-
- //Get the form data buffer (should be cost free)
- Memory<byte> formBuffer = context.Buffers.GetFormDataBuffer();
-
- Debug.Assert(!formBuffer.IsEmpty, "GetFormDataBuffer() returned an empty memory buffer");
switch (request.State.ContentType)
{
@@ -157,10 +153,9 @@ namespace VNLib.Net.Http.Core
case ContentType.UrlEncoded:
{
//Alloc the form data character buffer, this will need to grow if the form data is larger than the buffer
- using IResizeableMemoryHandle<char> urlbody = pool.AllocFormDataBuffer<char>(bufferSize);
-
- //Load char buffer from stream
- int chars = await BufferInputStream(request.InputStream, urlbody, formBuffer, info.Encoding);
+ using IResizeableMemoryHandle<char> urlbody = AllocFdBuffer(context);
+
+ int chars = await BufferInputStreamAsChars(request.InputStream, urlbody, GetFdBuffer(context), info.Encoding);
//Get the body as a span, and split the 'string' at the & character
((ReadOnlySpan<char>)urlbody.AsSpan(0, chars))
@@ -175,12 +170,10 @@ namespace VNLib.Net.Http.Core
{
break;
}
-
- //Alloc the form data buffer
- using IResizeableMemoryHandle<char> formBody = pool.AllocFormDataBuffer<char>(bufferSize);
-
- //Load char buffer from stream
- int chars = await BufferInputStream(request.InputStream, formBody, formBuffer, info.Encoding);
+
+ using IResizeableMemoryHandle<char> formBody = AllocFdBuffer(context);
+
+ int chars = await BufferInputStreamAsChars(request.InputStream, formBody, GetFdBuffer(context), info.Encoding);
//Split the body as a span at the boundries
((ReadOnlySpan<char>)formBody.AsSpan(0, chars))
@@ -194,6 +187,25 @@ namespace VNLib.Net.Http.Core
request.AddFileUpload(new(request.InputStream, false, request.State.ContentType, null));
break;
}
+
+
+ static IResizeableMemoryHandle<char> AllocFdBuffer(HttpContext context)
+ {
+ //Gets the max form data buffer size to help calculate the initial char buffer size
+ int maxBufferSize = context.ParentServer.Config.BufferConfig.FormDataBufferSize;
+
+ //Calculate a largest available buffer to read the entire stream or up to the maximum buffer size
+ int buffersize = (int)Math.Min(context.Request.InputStream.Length, maxBufferSize);
+
+ return context.ParentServer.Config.MemoryPool.AllocFormDataBuffer<char>(buffersize);
+ }
+
+ static Memory<byte> GetFdBuffer(HttpContext context)
+ {
+ Memory<byte> formBuffer = context.Buffers.GetFormDataBuffer();
+ Debug.Assert(!formBuffer.IsEmpty, "GetFormDataBuffer() returned an empty memory buffer");
+ return formBuffer;
+ }
}
/*
@@ -203,7 +215,12 @@ namespace VNLib.Net.Http.Core
* We assume the parsing method checked the size of the input stream so we can assume its safe to read
* all of it into memory.
*/
- private static async ValueTask<int> BufferInputStream(Stream stream, IResizeableMemoryHandle<char> charBuffer, Memory<byte> binBuffer, Encoding encoding)
+ private static async ValueTask<int> BufferInputStreamAsChars(
+ Stream stream,
+ IResizeableMemoryHandle<char> charBuffer,
+ Memory<byte> binBuffer,
+ Encoding encoding
+ )
{
int length = 0;
do
diff --git a/lib/Net.Http/src/Core/RequestParse/Http11ParseExtensions.cs b/lib/Net.Http/src/Core/RequestParse/Http11ParseExtensions.cs
index 86535c3..cabb723 100644
--- a/lib/Net.Http/src/Core/RequestParse/Http11ParseExtensions.cs
+++ b/lib/Net.Http/src/Core/RequestParse/Http11ParseExtensions.cs
@@ -117,7 +117,6 @@ namespace VNLib.Net.Http.Core
//Try to parse the requested http version, only supported versions
if ((reqState.HttpVersion = HttpHelpers.ParseHttpVersion(requestLine[endloc..])) == HttpVersion.None)
{
- //Return not supported
return HttpStatusCode.HttpVersionNotSupported;
}
@@ -450,18 +449,18 @@ namespace VNLib.Net.Http.Core
}
//Set full http range
- reqState.Range = new(startRangeValue, endRangeValue, HttpRangeType.FullRange);
+ reqState.Range = HttpRange.FullRange(startRangeValue, endRangeValue);
}
else
{
//From-end range
- reqState.Range = new(0, endRangeValue, HttpRangeType.FromEnd);
+ reqState.Range = HttpRange.FromEnd(endRangeValue);
}
}
else if(hasStartRange)
{
//Valid start range only, so from start range
- reqState.Range = new(startRangeValue, 0, HttpRangeType.FromStart);
+ reqState.Range = HttpRange.FromStart(startRangeValue);
}
//No valid range values
}
@@ -554,7 +553,10 @@ namespace VNLib.Net.Http.Core
//Bad format to include a message body with a GET, HEAD, or TRACE request
if (parseState.ContentLength > 0)
{
- Config.ServerLog.Debug("Message body received from {ip} with GET, HEAD, or TRACE request, was considered an error and the request was dropped", reqState.RemoteEndPoint);
+ Config.ServerLog.Debug(
+ "Message body received from {ip} with GET, HEAD, or TRACE request, was considered an error and the request was dropped",
+ reqState.RemoteEndPoint
+ );
return HttpStatusCode.BadRequest;
}
else
diff --git a/lib/Net.Http/src/Core/Response/HttpResponse.cs b/lib/Net.Http/src/Core/Response/HttpResponse.cs
index ec9879b..06f114c 100644
--- a/lib/Net.Http/src/Core/Response/HttpResponse.cs
+++ b/lib/Net.Http/src/Core/Response/HttpResponse.cs
@@ -119,10 +119,11 @@ namespace VNLib.Net.Http.Core.Response
//Write headers
for (int i = 0; i < Headers.Count; i++)
{
- writer.Append(Headers.Keys[i]); //Write header key
- writer.Append(": "); //Write separator
- writer.Append(Headers[i]); //Write the header value
- writer.Append(HttpHelpers.CRLF); //Crlf
+ //<name>: <value>\r\n
+ writer.Append(Headers.Keys[i]);
+ writer.Append(": ");
+ writer.Append(Headers[i]);
+ writer.Append(HttpHelpers.CRLF);
}
//Remove writen headers
@@ -131,7 +132,6 @@ namespace VNLib.Net.Http.Core.Response
//Write cookies if any are set
if (Cookies.Count > 0)
{
- //Enumerate and write
foreach (HttpCookie cookie in Cookies)
{
writer.Append("Set-Cookie: ");
@@ -141,8 +141,7 @@ namespace VNLib.Net.Http.Core.Response
writer.Append(HttpHelpers.CRLF);
}
-
- //Clear all current cookies
+
Cookies.Clear();
}
@@ -302,10 +301,9 @@ namespace VNLib.Net.Http.Core.Response
}
///<inheritdoc/>
- public void OnNewConnection()
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void OnNewConnection(Stream transport)
{
- //Get the transport stream and init streams
- Stream transport = ContextInfo.GetTransport();
ReusableChunkedStream.OnNewConnection(transport);
ReusableDirectStream.OnNewConnection(transport);
}
diff --git a/lib/Net.Http/src/Core/Response/HttpStreamResponse.cs b/lib/Net.Http/src/Core/Response/HttpStreamResponse.cs
index b08d2ab..679d8fe 100644
--- a/lib/Net.Http/src/Core/Response/HttpStreamResponse.cs
+++ b/lib/Net.Http/src/Core/Response/HttpStreamResponse.cs
@@ -22,13 +22,6 @@
* along with this program. If not, see https://www.gnu.org/licenses/.
*/
-/*
- * This file handles response entity processing. It handles in-memory response
- * processing, as well as stream response processing. It handles constraints
- * such as content-range limits. I tried to eliminate or reduce the amount of
- * memory copying required to process the response entity.
- */
-
using System;
using System.IO;
using System.Threading;
diff --git a/lib/Net.Http/src/Core/Response/HttpstreamResponse.cs b/lib/Net.Http/src/Core/Response/HttpstreamResponse.cs
index b08d2ab..679d8fe 100644
--- a/lib/Net.Http/src/Core/Response/HttpstreamResponse.cs
+++ b/lib/Net.Http/src/Core/Response/HttpstreamResponse.cs
@@ -22,13 +22,6 @@
* along with this program. If not, see https://www.gnu.org/licenses/.
*/
-/*
- * This file handles response entity processing. It handles in-memory response
- * processing, as well as stream response processing. It handles constraints
- * such as content-range limits. I tried to eliminate or reduce the amount of
- * memory copying required to process the response entity.
- */
-
using System;
using System.IO;
using System.Threading;
diff --git a/lib/Net.Http/src/Helpers/HttpRange.cs b/lib/Net.Http/src/Helpers/HttpRange.cs
index cedcc40..af8c8a8 100644
--- a/lib/Net.Http/src/Helpers/HttpRange.cs
+++ b/lib/Net.Http/src/Helpers/HttpRange.cs
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2023 Vaughn Nugent
+* Copyright (c) 2024 Vaughn Nugent
*
* Library: VNLib
* Package: VNLib.Net.Http
@@ -40,5 +40,12 @@ namespace VNLib.Net.Http
/// <param name="end">The ending range value</param>
/// <returns>True if the range values are valid, false otherwise</returns>
public static bool IsValidRangeValue(ulong start, ulong end) => start <= end;
+
+
+ internal static HttpRange FromStart(ulong start) => new(start, 0, HttpRangeType.FromStart);
+
+ internal static HttpRange FromEnd(ulong end) => new(0, end, HttpRangeType.FromEnd);
+
+ internal static HttpRange FullRange(ulong start, ulong end) => new(start, end, HttpRangeType.FullRange);
}
} \ No newline at end of file
diff --git a/lib/Net.Http/src/HttpBufferConfig.cs b/lib/Net.Http/src/HttpBufferConfig.cs
index fa3ad21..81fea12 100644
--- a/lib/Net.Http/src/HttpBufferConfig.cs
+++ b/lib/Net.Http/src/HttpBufferConfig.cs
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2023 Vaughn Nugent
+* Copyright (c) 2024 Vaughn Nugent
*
* Library: VNLib
* Package: VNLib.Net.Http
@@ -74,5 +74,11 @@ namespace VNLib.Net.Http
/// May be set to 0 when <see cref="HttpConfig.CompressorManager"/> is set to null (compression is disabled).
/// </summary>
public readonly int ChunkedResponseAccumulatorSize { get; init; } = 64 * 1024;
+
+ /// <summary>
+ /// When a transport connection is closed, dedicated buffers are released back to the
+ /// heap. This setting controls whether the buffers are all zeroed before being released.
+ /// </summary>
+ public readonly bool ZeroBuffersOnDisconnect { get; init; } = true;
}
} \ No newline at end of file