Skip to content

Commit

Permalink
wpi
Browse files Browse the repository at this point in the history
  • Loading branch information
CypherPotato committed Jan 22, 2025
1 parent 0d5bd03 commit aad3626
Show file tree
Hide file tree
Showing 9 changed files with 124 additions and 171 deletions.
60 changes: 0 additions & 60 deletions cadente/Sisk.Cadente/HighPerformance/ArrayPoolExtensions.cs

This file was deleted.

103 changes: 55 additions & 48 deletions cadente/Sisk.Cadente/HttpConnection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ sealed class HttpConnection : IDisposable {
public readonly int Id = 0;
#endif

public const int REQUEST_BUFFER_SIZE = 4096;
public const int REQUEST_BUFFER_SIZE = 8192; // buffer dedicated to headers. more than it? return 400.
public const int RESPONSE_BUFFER_SIZE = 8192;

public HttpAction Action { get; set; }
Expand All @@ -38,72 +38,79 @@ public async Task<HttpConnectionState> HandleConnectionEvents () {
ObjectDisposedException.ThrowIf ( this.disposedValue, this );

bool connectionCloseRequested = false;
byte [] buffer = ArrayPool<byte>.Shared.Rent ( REQUEST_BUFFER_SIZE );
var bufferOwnership = MemoryPool<byte>.Shared.Rent ( REQUEST_BUFFER_SIZE );
try {

while (this._connectionStream.CanRead && !this.disposedValue) {
while (this._connectionStream.CanRead && !this.disposedValue) {

HttpRequestReader requestReader = new HttpRequestReader ( this._connectionStream, ref buffer );
Stream? responseStream = null;
HttpRequestReader requestReader = new HttpRequestReader ( this._connectionStream, ref bufferOwnership );
Stream? responseStream = null;

try {
try {

var readRequestState = await requestReader.ReadHttpRequest ();
var nextRequest = readRequestState.Item2;
var readRequestState = await requestReader.ReadHttpRequest ();
var nextRequest = readRequestState.Item2;

if (nextRequest is null) {
return readRequestState.Item1 switch {
HttpRequestReadState.StreamZero => HttpConnectionState.ConnectionClosedByStreamRead,
_ => HttpConnectionState.BadRequest
};
}
if (nextRequest is null) {
return readRequestState.Item1 switch {
HttpRequestReadState.StreamZero => HttpConnectionState.ConnectionClosedByStreamRead,
_ => HttpConnectionState.BadRequest
};
}

//Logger.LogInformation ( $"[{this.Id}] Received \"{nextRequest.Method} {nextRequest.Path}\"" );
HttpSession managedSession = new HttpSession ( nextRequest, this._connectionStream );
//Logger.LogInformation ( $"[{this.Id}] Received \"{nextRequest.Method} {nextRequest.Path}\"" );
HttpSession managedSession = new HttpSession ( nextRequest, this._connectionStream );

this.Action ( managedSession );
this.Action ( managedSession );

if (!managedSession.KeepAlive || !nextRequest.CanKeepAlive) {
connectionCloseRequested = true;
managedSession.Response.Headers.Set ( new HttpHeader ( HttpHeaderName.Connection, "close" ) );
}
if (!managedSession.KeepAlive || !nextRequest.CanKeepAlive) {
connectionCloseRequested = true;
managedSession.Response.Headers.Set ( new HttpHeader ( HttpHeaderName.Connection, "close" ) );
}

if (managedSession.Response.ResponseStream is Stream { } s) {
responseStream = s;
}
else {
managedSession.Response.Headers.Set ( new HttpHeader ( HttpHeaderName.ContentLength, "0" ) );
}
if (managedSession.Response.ResponseStream is Stream { } s) {
responseStream = s;
}
else {
managedSession.Response.Headers.Set ( new HttpHeader ( HttpHeaderName.ContentLength, "0" ) );
}

Stream outputStream = this._connectionStream;
if (responseStream is not null) {
Stream outputStream = this._connectionStream;
if (responseStream is not null) {

if (managedSession.Response.SendChunked || !responseStream.CanSeek) {
managedSession.Response.Headers.Set ( new HttpHeader ( HttpHeaderName.TransferEncoding, "chunked" );
responseStream = new HttpChunkedStream ( responseStream );
if (managedSession.Response.SendChunked || !responseStream.CanSeek) {
managedSession.Response.Headers.Set ( new HttpHeader ( HttpHeaderName.TransferEncoding, "chunked" ) );
responseStream = new HttpChunkedStream ( responseStream );
}
else {
managedSession.Response.Headers.Set ( new HttpHeader ( HttpHeaderName.ContentLength, responseStream.Length.ToString () ) );
}
}
}

if (managedSession.ResponseHeadersAlreadySent == false && !await managedSession.WriteHttpResponseHeaders ()) {
return HttpConnectionState.ResponseWriteException;
}
if (managedSession.ResponseHeadersAlreadySent == false && !await managedSession.WriteHttpResponseHeaders ()) {
return HttpConnectionState.ResponseWriteException;
}

if (responseStream is not null) {
await responseStream.CopyToAsync ( outputStream );
}
if (responseStream is not null) {
await responseStream.CopyToAsync ( outputStream );
}

this._connectionStream.Flush ();
this._connectionStream.Flush ();

if (connectionCloseRequested) {
break;
if (connectionCloseRequested) {
break;
}
}
finally {
responseStream?.Dispose ();
}
}
finally {
responseStream?.Dispose ();
ArrayPool<byte>.Shared.Return ( buffer );
}
}

return HttpConnectionState.ConnectionClosed;
return HttpConnectionState.ConnectionClosed;
}
finally {
bufferOwnership.Dispose ();
}
}

private void Dispose ( bool disposing ) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,13 @@

using System.Text;

namespace Sisk.Cadente.HttpSerializer;
namespace Sisk.Cadente;

/// <summary>
/// Represents an HTTP header, consisting of a name and a value.
/// </summary>
public readonly struct HttpHeader {

internal readonly ReadOnlyMemory<byte> NameBytes;
internal readonly ReadOnlyMemory<byte> ValueBytes;

Expand Down Expand Up @@ -57,4 +58,11 @@ public string Value {
return HeaderEncoding.GetString ( this.ValueBytes.Span );
}
}

/// <summary>
/// Gets the string representation of this <see cref="HttpHeader"/>.
/// </summary>
public override string ToString () {
return $"{this.Name}: {this.Value}";
}
}
2 changes: 1 addition & 1 deletion cadente/Sisk.Cadente/HttpHost.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ namespace Sisk.Cadente;
/// </summary>
public sealed class HttpHost : IDisposable {

const int QUEUE_SIZE = 256;
const int QUEUE_SIZE = 1024;

private readonly TcpListener _listener;
private readonly Channel<TcpClient> clientQueue;
Expand Down
12 changes: 7 additions & 5 deletions cadente/Sisk.Cadente/HttpRequest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,18 @@ namespace Sisk.Cadente;
/// Represents an HTTP request.
/// </summary>
public sealed class HttpRequest {

private HttpRequestBase _baseRequest;

/// <summary>
/// Gets the HTTP method (e.g., GET, POST) of the request.
/// </summary>
public string Method { get; }
public string Method { get => this._baseRequest.Method; }

/// <summary>
/// Gets the path of the requested resource.
/// </summary>
public string Path { get; }
public string Path { get => this._baseRequest.Path; }

/// <summary>
/// Gets the content length of the request.
Expand All @@ -44,9 +47,8 @@ public sealed class HttpRequest {
internal HttpRequest ( HttpRequestBase request, HttpRequestStream requestStream ) {
this.ContentLength = requestStream.Length;

this.Method = request.Method;
this.Path = request.Path;
this.Headers = request.Headers;
this._baseRequest = request;
this.Headers = this._baseRequest.Headers.ToArray ();
this.ContentStream = requestStream;
}
}
34 changes: 23 additions & 11 deletions cadente/Sisk.Cadente/HttpSerializer/HttpRequestBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,23 +7,35 @@
// File name: HttpRequestBase.cs
// Repository: https://github.com/sisk-http/core

using System.Text;

namespace Sisk.Cadente.HttpSerializer;

class HttpRequestBase {
public required string Method;
public required string Path;
public required string Version;
private string? _method;
private string? _path;

public required HttpHeader [] Headers;
public required ReadOnlyMemory<byte> MethodRef;
public required ReadOnlyMemory<byte> PathRef;

public long ContentLength;
public required ReadOnlyMemory<HttpHeader> Headers;

public string Method {
get {
this._method ??= Encoding.ASCII.GetString ( this.MethodRef.Span );
return this._method;
}
}

public string Path {
get {
this._path ??= Encoding.ASCII.GetString ( this.PathRef.Span );
return this._path;
}
}

public long ContentLength;
public bool CanKeepAlive;

/// <summary>
/// Gets the index in the <see cref="BufferedContent"/> where the header parsing is terminated, including
/// the lasts CRLF.
/// </summary>
public int BufferHeaderIndex;
public required byte [] BufferedContent;
public required ReadOnlyMemory<byte> BufferedContent;
}
Loading

0 comments on commit aad3626

Please sign in to comment.