Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
CypherPotato committed Dec 25, 2024
1 parent e7940f3 commit 7442510
Show file tree
Hide file tree
Showing 7 changed files with 101 additions and 16 deletions.
6 changes: 3 additions & 3 deletions tcp/Sisk.ManagedHttpListener/HttpConnection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ public async Task<HttpConnectionState> HandleConnectionEvents () {
};
}

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

this.Action ( managedSession );
Expand Down Expand Up @@ -89,7 +89,7 @@ public async Task<HttpConnectionState> HandleConnectionEvents () {
managedSession.Response.Headers.Set ( new HttpHeader ( "Content-Length", "0" ) );
}

if (await HttpResponseSerializer.WriteHttpResponseHeaders ( this._connectionStream, managedSession.Response ) == false) {
if (!managedSession.ResponseHeadersAlreadySent && !await managedSession.WriteHttpResponseHeaders ()) {

return HttpConnectionState.ResponseWriteException;
}
Expand All @@ -103,7 +103,7 @@ public async Task<HttpConnectionState> HandleConnectionEvents () {

this._connectionStream.Flush ();

Logger.LogInformation ( $"[{this.Id}] Response sent: {managedSession.Response.StatusCode} {managedSession.Response.StatusDescription}" );
//Logger.LogInformation ( $"[{this.Id}] Response sent: {managedSession.Response.StatusCode} {managedSession.Response.StatusDescription}" );

if (connectionCloseRequested) {
break;
Expand Down
32 changes: 32 additions & 0 deletions tcp/Sisk.ManagedHttpListener/HttpEventStreamWriter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// The Sisk Framework source code
// Copyright (c) 2024- PROJECT PRINCIPIUM and all Sisk contributors
//
// The code below is licensed under the MIT license as
// of the date of its publication, available at
//
// File name: HttpEventStreamWriter.cs
// Repository: https://github.com/sisk-http/core

using System.Text;

namespace Sisk.ManagedHttpListener;

public sealed class HttpEventStreamWriter {
private Stream _innerStream;
private Encoding _messageEncoding;

internal HttpEventStreamWriter ( Stream innerStream, Encoding encoding ) {
this._innerStream = innerStream;
this._messageEncoding = encoding;
}

public async Task WriteDataAsync ( string data ) {
byte [] payload = this._messageEncoding.GetBytes ( $"data: {data}\n\n" );
await this._innerStream.WriteAsync ( payload );
}

public async Task WriteEventAsync ( string eventName ) {
byte [] payload = this._messageEncoding.GetBytes ( $"event: {eventName}\n\n" );
await this._innerStream.WriteAsync ( payload );
}
}
8 changes: 4 additions & 4 deletions tcp/Sisk.ManagedHttpListener/HttpHost.cs
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ private async Task HandleTcpClient ( TcpClient client ) {
using (HttpConnection connection = new HttpConnection ( connectionStream, this.ActionHandler )) {

if (connectionStream is SslStream sslStream && this.HttpsOptions is not null) {
Logger.LogInformation ( $"[{connection.Id}] Begin SSL authenticate" );
//Logger.LogInformation ( $"[{connection.Id}] Begin SSL authenticate" );
try {
await sslStream.AuthenticateAsServerAsync (
serverCertificate: this.HttpsOptions.ServerCertificate,
Expand All @@ -99,14 +99,14 @@ await sslStream.AuthenticateAsServerAsync (
enabledSslProtocols: this.HttpsOptions.AllowedProtocols );
}
catch (Exception ex) {
Logger.LogInformation ( $"[{connection.Id}] Failed SSL authenticate: {ex.Message}" );
//Logger.LogInformation ( $"[{connection.Id}] Failed SSL authenticate: {ex.Message}" );
}
}

Logger.LogInformation ( $"[{connection.Id}] Begin handle connection" );
//Logger.LogInformation ( $"[{connection.Id}] Begin handle connection" );
var state = await connection.HandleConnectionEvents ();

Logger.LogInformation ( $"[{connection.Id}] Ended handling connection with state {state}" );
//Logger.LogInformation ( $"[{connection.Id}] Ended handling connection with state {state}" );

}
}
Expand Down
36 changes: 34 additions & 2 deletions tcp/Sisk.ManagedHttpListener/HttpResponse.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,15 @@
// File name: HttpResponse.cs
// Repository: https://github.com/sisk-http/core

using System.Text;
using Sisk.ManagedHttpListener.HttpSerializer;

namespace Sisk.ManagedHttpListener;

public sealed class HttpResponse {
private Stream _baseOutputStream;
private HttpSession _session;

public int StatusCode { get; set; }
public string StatusDescription { get; set; }
public List<HttpHeader> Headers { get; set; }
Expand All @@ -22,12 +26,40 @@ public sealed class HttpResponse {
public Stream? ResponseStream { get; set; }
public byte []? ResponseBytes { get; set; }

internal HttpResponse () {
public Task<HttpEventStreamWriter> GetEventStreamAsync () => this.GetEventStreamAsync ( Encoding.UTF8 );

public async Task<HttpEventStreamWriter> GetEventStreamAsync ( Encoding encoding ) {
this.Headers.Set ( new HttpHeader ( "Content-Type", "text/event-stream" ) );
this.Headers.Set ( new HttpHeader ( "Cache-Control", "no-cache" ) );

if (await this._session.WriteHttpResponseHeaders () == false) {
throw new InvalidOperationException ( "Unable to obtain an output stream for the response." );
}

return new HttpEventStreamWriter ( this._baseOutputStream, encoding );
}

public async Task<Stream> GetContentStream () {
if (await this._session.WriteHttpResponseHeaders () == false) {
throw new InvalidOperationException ( "Unable to obtain an output stream for the response." );
}

this.ResponseStream = null;
this.ResponseBytes = null;

return this._baseOutputStream;
}

internal HttpResponse ( HttpSession session, Stream httpSessionStream ) {
this._session = session;
this._baseOutputStream = httpSessionStream;

this.StatusCode = 200;
this.StatusDescription = "Ok";

this.Headers = new List<HttpHeader>
{
new HttpHeader ("Date", DateTime.Now.ToString("R")),
new HttpHeader ("Date", DateTime.UtcNow.ToString("R")),
new HttpHeader ("Server", "Sisk")
};
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,15 +121,18 @@ public HttpRequestReader ( Stream stream, ref byte [] buffer ) {

// checks whether the current buffer has all the request headers. if not, read more data from the buffer
int bufferLength = buffer.Length;
if (i + BUFFER_LOOKAHEAD_OFFSET > bufferLength && !requestStreamFinished) {

if (!requestStreamFinished && i + BUFFER_LOOKAHEAD_OFFSET > bufferLength) {
ArrayPool<byte>.Shared.Resize ( ref inputBuffer, inputBuffer.Length * 2, clearArray: false );
int count = inputBuffer.Length - bufferLength;
int read = this._stream.Read ( inputBuffer, bufferLength - 1, count );

if (read > 0) {
buffer = inputBuffer; // recreate the span over the input buffer
firstByte = ref MemoryMarshal.GetReference ( buffer );
length += read;
}

if (read < count) {
requestStreamFinished = true;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@ internal static class HttpResponseSerializer {

public static async Task<bool> WriteHttpResponseHeaders ( Stream outgoingStream, HttpResponse response ) {
try {
using var ms = new MemoryStream ( 1024 );
const int BUFFER_SIZE = 2048;

using var ms = new MemoryStream ( BUFFER_SIZE );
const byte SPACE = 0x20;

ms.Write ( "HTTP/1.1 "u8 );
Expand All @@ -36,12 +38,12 @@ public static async Task<bool> WriteHttpResponseHeaders ( Stream outgoingStream,
ms.Write ( "\r\n"u8 );

ms.Position = 0;
await ms.CopyToAsync ( outgoingStream );
await ms.CopyToAsync ( outgoingStream, BUFFER_SIZE );

return true;
}
catch (Exception ex) {
Logger.LogInformation ( $"HttpResponseSerializer finished with exception: {ex.Message}" );
//Logger.LogInformation ( $"HttpResponseSerializer finished with exception: {ex.Message}" );
return false;
}
}
Expand Down
22 changes: 19 additions & 3 deletions tcp/Sisk.ManagedHttpListener/HttpSession.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,30 @@
namespace Sisk.ManagedHttpListener;

public sealed class HttpSession {

private Stream _connectionStream;
internal bool ResponseHeadersAlreadySent = false;

internal Task<bool> WriteHttpResponseHeaders () {
if (this.ResponseHeadersAlreadySent) {
return Task.FromResult ( true );
}

this.ResponseHeadersAlreadySent = true;
return HttpResponseSerializer.WriteHttpResponseHeaders ( this._connectionStream, this.Response );
}


public HttpRequest Request { get; }
public HttpResponse Response { get; }

public bool KeepAlive { get; set; } = true;

internal HttpSession ( HttpRequestBase baseRequest, Stream contentStream ) {
HttpRequestStream requestStream = new HttpRequestStream ( contentStream, baseRequest );
internal HttpSession ( HttpRequestBase baseRequest, Stream connectionStream ) {
this._connectionStream = connectionStream;

HttpRequestStream requestStream = new HttpRequestStream ( connectionStream, baseRequest );
this.Request = new HttpRequest ( baseRequest, requestStream );
this.Response = new HttpResponse ();
this.Response = new HttpResponse ( this, connectionStream );
}
}

0 comments on commit 7442510

Please sign in to comment.