Skip to content

Commit

Permalink
fix sslproxy chunked reader
Browse files Browse the repository at this point in the history
  • Loading branch information
CypherPotato committed Sep 1, 2024
1 parent 8aeda49 commit e5b6f51
Show file tree
Hide file tree
Showing 11 changed files with 158 additions and 121 deletions.
52 changes: 0 additions & 52 deletions core.sln

This file was deleted.

6 changes: 3 additions & 3 deletions extensions/Sisk.IniConfiguration/Sisk.IniConfiguration.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@
<PackageTags>http-server,http,web framework</PackageTags>
<RepositoryType>git</RepositoryType>

<Version>1.0.0.0</Version>
<AssemblyVersion>1.0.0.0</AssemblyVersion>
<FileVersion>1.0.0.0</FileVersion>
<Version>1.0.1.0</Version>
<AssemblyVersion>1.0.1.0</AssemblyVersion>
<FileVersion>1.0.1.0</FileVersion>

<NeutralLanguage>en</NeutralLanguage>
<PackageLicenseFile>LICENSE.txt</PackageLicenseFile>
Expand Down
4 changes: 2 additions & 2 deletions extensions/Sisk.SslProxy/SerializerUtils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,10 @@ public static void CopyBlocking(Stream input, Stream output, EventWaitHandle wai
callback = ar =>
{
int bytesRead = input.EndRead(ar);
output.Write(buffer, 0, bytesRead);

if (bytesRead > 0)
{
output.Write(buffer, 0, bytesRead);
input.BeginRead(buffer, 0, buffer.Length, callback, null);
}
else
Expand All @@ -69,11 +69,11 @@ public static void CopyUntilBlocking(Stream input, Stream output, byte[] eof, Ev
callback = ar =>
{
int bytesRead = input.EndRead(ar);
output.Write(buffer, 0, bytesRead);

ReadOnlySpan<byte> writtenSpan = buffer[0..bytesRead];
if (bytesRead > 0 && !writtenSpan.EndsWith(eof))
{
output.Write(buffer, 0, bytesRead);
input.BeginRead(buffer, 0, buffer.Length, callback, null);
}
else
Expand Down
3 changes: 2 additions & 1 deletion extensions/Sisk.SslProxy/SslProxy.cs
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,8 @@ void ReceiveClientAsync(IAsyncResult ar)
// TODO: check if client wants to keep alive
if (isConnectionKeepAlive)
{
resHeaders.Add(("Connection", "keep-alive"));
// not necessary in HTTP/1.1
// resHeaders.Add(("Connection", "keep-alive"));
}
else
{
Expand Down
23 changes: 23 additions & 0 deletions src/Entity/StringValue.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,29 @@ internal StringValue(string name, string type, string? data)
this.argType = type;
}

/// <summary>
/// Creates an new empty value of the <see cref="StringValue"/> with no predefined value.
/// </summary>
/// <param name="name">The <see cref="StringValue"/> name.</param>
public StringValue(string name)
{
this._ref = null;
this.argName = name;
this.argType = "StringValue";
}

/// <summary>
/// Creates an new value of the <see cref="StringValue"/>.
/// </summary>
/// <param name="name">The <see cref="StringValue"/> name.</param>
/// <param name="value">The <see cref="StringValue"/> value.</param>
public StringValue(string name, string? value)
{
this._ref = value;
this.argName = name;
this.argType = "StringValue";
}

/// <summary>
/// Gets the name of the property that hosts this <see cref="StringValue"/>.
/// </summary>
Expand Down
10 changes: 10 additions & 0 deletions src/Entity/StringValueCollection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,16 @@ internal static StringValueCollection FromNameValueCollection(string paramName,
return vcol;
}

/// <summary>
/// Creates an new <see cref="StringValueCollection"/> instance with values from another
/// <see cref="IDictionary"/> instance.
/// </summary>
public StringValueCollection(IDictionary<string, string?> values)
{
this.items = new Dictionary<string, string?>(values, StringComparer.OrdinalIgnoreCase);
this.paramName = "StringValue";
}

internal StringValueCollection(string paramName)
{
this.items = new Dictionary<string, string?>(StringComparer.OrdinalIgnoreCase);
Expand Down
52 changes: 35 additions & 17 deletions src/Http/Handlers/HttpServerHandlerRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,26 @@
// File name: HttpServerHandlerRepository.cs
// Repository: https://github.com/sisk-http/core

using Sisk.Core.Entity;
using Sisk.Core.Routing;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using Sisk.Core.Entity;
using Sisk.Core.Routing;

namespace Sisk.Core.Http.Handlers;

enum HttpServerHandlerActionEvent
{
ServerStarting,
ServerStarted,
SetupRouter,
ContextBagCreated,
HttpRequestOpen,
HttpRequestClose,
Exception,
Stopping,
Stopped,
}

internal class HttpServerHandlerRepository
{
private readonly HttpServer parent;
Expand All @@ -23,17 +36,22 @@ internal class HttpServerHandlerRepository
public HttpServerHandlerRepository(HttpServer parent)
{
this.parent = parent;
this.RegisterHandler(this._default);
RegisterHandler(_default);
}

public void RegisterHandler(HttpServerHandler handler)
{
this.handlers.Add(handler);
handlers.Add(handler);
}

private void CallEvery(Action<HttpServerHandler> action)
private bool IsEventBreakable(HttpServerHandlerActionEvent eventName)
=> eventName == HttpServerHandlerActionEvent.ServerStarting
|| eventName == HttpServerHandlerActionEvent.ServerStarted
|| eventName == HttpServerHandlerActionEvent.SetupRouter;

private void CallEvery(Action<HttpServerHandler> action, HttpServerHandlerActionEvent eventName)
{
Span<HttpServerHandler> hspan = CollectionsMarshal.AsSpan(this.handlers);
Span<HttpServerHandler> hspan = CollectionsMarshal.AsSpan(handlers);
ref HttpServerHandler hpointer = ref MemoryMarshal.GetReference(hspan);
for (int i = 0; i < hspan.Length; i++)
{
Expand All @@ -45,22 +63,22 @@ private void CallEvery(Action<HttpServerHandler> action)
}
catch (Exception ex)
{
if (!this.parent.ServerConfiguration.ThrowExceptions)
if (parent.ServerConfiguration.ThrowExceptions == false && IsEventBreakable(eventName) == false)
{
this.parent.ServerConfiguration.ErrorsLogsStream?.WriteException(ex);
parent.ServerConfiguration.ErrorsLogsStream?.WriteException(ex);
}
else throw;
}
}
}

internal void ServerStarting(HttpServer val) => this.CallEvery(handler => handler.InvokeOnServerStarting(val));
internal void ServerStarted(HttpServer val) => this.CallEvery(handler => handler.InvokeOnServerStarted(val));
internal void SetupRouter(Router val) => this.CallEvery(handler => handler.InvokeOnSetupRouter(val));
internal void ContextBagCreated(TypedValueDictionary val) => this.CallEvery(handler => handler.InvokeOnContextBagCreated(val));
internal void HttpRequestOpen(HttpRequest val) => this.CallEvery(handler => handler.InvokeOnHttpRequestOpen(val));
internal void HttpRequestClose(HttpServerExecutionResult val) => this.CallEvery(handler => handler.InvokeOnHttpRequestClose(val));
internal void Exception(Exception val) => this.CallEvery(handler => handler.InvokeOnException(val));
internal void Stopping(HttpServer val) => this.CallEvery(handler => handler.InvokeOnServerStopping(val));
internal void Stopped(HttpServer val) => this.CallEvery(handler => handler.InvokeOnServerStopped(val));
internal void ServerStarting(HttpServer val) => CallEvery(handler => handler.InvokeOnServerStarting(val), HttpServerHandlerActionEvent.ServerStarting);
internal void ServerStarted(HttpServer val) => CallEvery(handler => handler.InvokeOnServerStarted(val), HttpServerHandlerActionEvent.ServerStarted);
internal void SetupRouter(Router val) => CallEvery(handler => handler.InvokeOnSetupRouter(val), HttpServerHandlerActionEvent.SetupRouter);
internal void ContextBagCreated(TypedValueDictionary val) => CallEvery(handler => handler.InvokeOnContextBagCreated(val), HttpServerHandlerActionEvent.ContextBagCreated);
internal void HttpRequestOpen(HttpRequest val) => CallEvery(handler => handler.InvokeOnHttpRequestOpen(val), HttpServerHandlerActionEvent.HttpRequestOpen);
internal void HttpRequestClose(HttpServerExecutionResult val) => CallEvery(handler => handler.InvokeOnHttpRequestClose(val), HttpServerHandlerActionEvent.HttpRequestClose);
internal void Exception(Exception val) => CallEvery(handler => handler.InvokeOnException(val), HttpServerHandlerActionEvent.Exception);
internal void Stopping(HttpServer val) => CallEvery(handler => handler.InvokeOnServerStopping(val), HttpServerHandlerActionEvent.Stopping);
internal void Stopped(HttpServer val) => CallEvery(handler => handler.InvokeOnServerStopped(val), HttpServerHandlerActionEvent.Stopped);
}
34 changes: 17 additions & 17 deletions src/Http/Hosting/PortableConfigurationBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
// File name: PortableConfigurationBuilder.cs
// Repository: https://github.com/sisk-http/core

using Sisk.Core.Internal.ServiceProvider;
using System.ComponentModel;
using Sisk.Core.Internal.ServiceProvider;

namespace Sisk.Core.Http.Hosting;

Expand All @@ -26,44 +26,44 @@ public sealed class PortableConfigurationBuilder

internal PortableConfigurationBuilder(HttpServerHostContext context)
{
this._context = context;
_context = context;
}

internal void Build()
{
if (this._createIfDontExists && !File.Exists(this._filename))
if (_createIfDontExists && !File.Exists(_filename))
{
File.Create(this._filename).Close();
File.Create(_filename).Close();
}

ConfigurationContext provider = new ConfigurationContext(this._filename, this._context, this._context.ServerConfiguration.ListeningHosts[0]);
ConfigurationContext provider = new ConfigurationContext(_filename, _context, _context.ServerConfiguration.ListeningHosts[0]);

var pipelineReader = this._pipeline ?? new JsonConfigParser();
var pipelineReader = _pipeline ?? new JsonConfigParser();
pipelineReader.ReadConfiguration(provider);

if (this._initializerHandler != null)
this._initializerHandler(this._context.Parameters);
if (_initializerHandler != null)
_initializerHandler(_context.Parameters);

this._context.Parameters.MakeReadonly();
_context.Parameters.MakeReadonly();
}

/// <summary>
/// Defines an custom <see cref="IConfigurationReader"/> configuration pipeline to the builder.
/// </summary>
/// <param name="reader">The <see cref="IConfigurationReader"/> object.</param>
public PortableConfigurationBuilder WithConfigurationReader(IConfigurationReader reader)
public PortableConfigurationBuilder WithConfigReader(IConfigurationReader reader)
{
this._pipeline = reader;
_pipeline = reader;
return this;
}

/// <summary>
/// Defines an custom <see cref="IConfigurationReader"/> configuration pipeline to the builder.
/// </summary>
/// <typeparam name="TPipeline">The <see cref="IConfigurationReader"/> type.</typeparam>
public PortableConfigurationBuilder WithConfigurationPipeline<TPipeline>() where TPipeline : IConfigurationReader, new()
/// <typeparam name="TReader">The <see cref="IConfigurationReader"/> type.</typeparam>
public PortableConfigurationBuilder WithConfigReader<TReader>() where TReader : IConfigurationReader, new()
{
this._pipeline = new TPipeline();
_pipeline = new TReader();
return this;
}

Expand All @@ -74,8 +74,8 @@ public PortableConfigurationBuilder WithConfigurationReader(IConfigurationReader
/// <param name="createIfDontExists">Optional. Determines if the configuration file should be created if it doens't exists.</param>
public PortableConfigurationBuilder WithConfigFile(string filename, bool createIfDontExists = false)
{
this._filename = Path.GetFullPath(filename);
this._createIfDontExists = createIfDontExists;
_filename = Path.GetFullPath(filename);
_createIfDontExists = createIfDontExists;
return this;
}

Expand All @@ -85,7 +85,7 @@ public PortableConfigurationBuilder WithConfigFile(string filename, bool createI
/// <param name="handler">The handler of <see cref="InitializationParameterCollection"/>.</param>
public PortableConfigurationBuilder WithParameters(Action<InitializationParameterCollection> handler)
{
this._initializerHandler = handler;
_initializerHandler = handler;
return this;
}

Expand Down
48 changes: 46 additions & 2 deletions src/Http/Streams/HttpWebSocket.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,11 @@ public sealed class HttpWebSocket
/// </summary>
public HttpStreamPingPolicy PingPolicy => this.pingPolicy;

/// <summary>
/// Gets or sets the maximum wait time for synchronous listener methods like <see cref="WaitNext()"/>.
/// </summary>
public TimeSpan WaitTimeout { get; set; } = TimeSpan.FromSeconds(60);

/// <summary>
/// Gets or sets the maximum number of attempts to send a failed message before the server closes the connection. Set it to -1 to
/// don't close the connection on failed attempts.
Expand Down Expand Up @@ -174,9 +179,33 @@ internal async void ReceiveTask()
/// Configures the ping policy for this instance of HTTP Web Socket.
/// </summary>
/// <param name="act">The method that runs on the ping policy for this HTTP Web Socket.</param>
public void WithPing(Action<HttpStreamPingPolicy> act)
public HttpWebSocket WithPing(Action<HttpStreamPingPolicy> act)
{
act(this.pingPolicy);
return this;
}

/// <summary>
/// Configures the ping policy for this instance of HTTP Web Socket.
/// </summary>
/// <param name="probeMessage">The payload/probe message that is sent to the client.</param>
/// <param name="interval">The sending interval for each probe message.</param>
public HttpWebSocket WithPing(string probeMessage, TimeSpan interval)
{
this.PingPolicy.DataMessage = probeMessage;
this.PingPolicy.Interval = interval;
this.PingPolicy.Start();
return this;
}

/// <summary>
/// Sends an text message to the remote point.
/// </summary>
/// <param name="message">The target message which will be as an encoded UTF-8 string.</param>
public void Send(object? message)
{
string? t = message?.ToString();
this.Send(t ?? string.Empty);
}

/// <summary>
Expand Down Expand Up @@ -325,10 +354,25 @@ public void WaitForClose()
/// Null is returned if a connection error is thrown.
/// </remarks>
public WebSocketMessage? WaitNext()
{
return this.WaitNext(this.WaitTimeout);
}

/// <summary>
/// Blocks the current thread and waits the next incoming message from this web socket instance within
/// the maximum defined timeout.
/// </summary>
/// <param name="timeout">The maximum time to wait until the next message.</param>
/// <remarks>
/// Null is returned if a connection error is thrown.
/// </remarks>
public WebSocketMessage? WaitNext(TimeSpan timeout)
{
this.waitNextEvent.Reset();
this.isWaitingNext = true;
this.waitNextEvent.WaitOne();

this.waitNextEvent.WaitOne(timeout);

return this.lastMessage;
}
}
Expand Down
Loading

0 comments on commit e5b6f51

Please sign in to comment.